문제
누구든지 어떻게하는지 설명 할 수 있습니다 foldr
일하다?
이 예제를 가져옵니다.
Prelude> foldr (-) 54 [10, 11]
53
Prelude> foldr (\x y -> (x+y)/2) 54 [12, 4, 10, 6]
12.0
나는이 처형에 대해 혼란스러워한다. 제안이 있습니까?
해결책
foldr
목록의 오른쪽 끝에서 시작하여 각 목록 항목을 제공 한 함수를 사용하여 축합기 값과 결합합니다. 결과는 모든 목록 요소에서 "폴딩"후 누산기의 최종 값입니다. 그것의 유형은 다음과 같습니다.
foldr :: (a -> b -> b) -> b -> [a] -> b
그리고 이것으로부터 당신은 목록 요소 (유형의 a
)은 주어진 함수에 대한 첫 번째 인수이며 축적기 (유형 b
) 두 번째입니다.
첫 번째 예제 :
Starting accumulator = 54
11 - 54 = -43
10 - (-43) = 53
^ Result from the previous line
^ Next list item
그래서 당신이받은 대답은 53이었습니다.
두 번째 예 :
Starting accumulator = 54
(6 + 54) / 2 = 30
(10 + 30) / 2 = 20
(4 + 20) / 2 = 12
(12 + 12) / 2 = 12
결과는 12입니다.
편집 : 나는 유한 한 목록을위한 것입니다. foldr
무한한 목록에서도 작동 할 수 있지만 먼저 유한 한 케이스를 둘러싼 것이 가장 좋습니다.
다른 팁
Foldr를 이해하는 가장 쉬운 방법은 설탕없이 접힌 목록을 다시 작성하는 것입니다.
[1,2,3,4,5] => 1:(2:(3:(4:(5:[]))))
이제 뭐 foldr f x
그렇게하는 것은 각각을 대체한다는 것입니다 :
~와 함께 f
Infix 양식 및 []
~와 함께 x
결과를 평가합니다.
예를 들어:
sum [1,2,3] = foldr (+) 0 [1,2,3]
[1,2,3] === 1:(2:(3:[]))
그래서
sum [1,2,3] === 1+(2+(3+0)) = 6
그것은 구별을 이해하는 데 도움이됩니다 foldr
그리고 foldl
. 왜 foldr
"오른쪽 접기"라고?
처음에 나는 그것이 오른쪽에서 왼쪽으로 요소를 소비했기 때문이라고 생각했습니다. 그러나 둘 다 foldr
그리고 foldl
왼쪽에서 오른쪽으로 목록을 소비하십시오.
foldl
평가합니다 왼쪽에서 오른쪽으로 (왼쪽 관련)foldr
평가합니다 오른쪽에서 왼쪽으로 (오른쪽 관련)
우리는 연관성이 중요한 연산자를 사용하는 예제 로이 차이를 명확하게 할 수 있습니다. 우리는 연산자 "Eats"와 같은 인간의 예를 사용할 수 있습니다.
foodChain = (human : (shark : (fish : (algae : []))))
foldl step [] foodChain
where step eater food = eater `eats` food -- note that "eater" is the accumulator and "food" is the element
foldl `eats` [] (human : (shark : (fish : (algae : []))))
== foldl eats (human `eats` shark) (fish : (algae : []))
== foldl eats ((human `eats` shark) `eats` fish) (algae : [])
== foldl eats (((human `eats` shark) `eats` fish) `eats` algae) []
== (((human `eats` shark) `eats` fish) `eats` algae)
이것의 의미론 foldl
IS : 인간은 상어를 먹은 다음 상어를 먹은 동일한 인간이 물고기를 먹습니다. 먹는 사람은 축적기입니다.
이것을 다음과 대조하십시오.
foldr step [] foodChain
where step food eater = eater `eats` food. -- note that "eater" is the element and "food" is the accumulator
foldr `eats` [] (human : (shark : (fish : (algae : []))))
== foldr eats (human `eats` shark) (fish : (algae : []))))
== foldr eats (human `eats` (shark `eats` (fish)) (algae : [])
== foldr eats (human `eats` (shark `eats` (fish `eats` algae))) []
== (human `eats` (shark `eats` (fish `eats` algae)
이것의 의미론 foldr
IS : 인간은 이미 조류를 먹은 물고기를 이미 먹은 상어를 먹습니다. 음식은 축합기입니다.
둘 다 foldl
그리고 foldr
왼쪽에서 오른쪽으로 "껍질을 벗기"이터를 먹기 때문에 Foldl을 "Left Fold"라고하는 이유는 아닙니다. 대신, 평가 순서가 중요합니다.
생각하십시오 foldr
매우 정의:
-- if the list is empty, the result is the initial value z
foldr f z [] = z
-- if not, apply f to the first element and the result of folding the rest
foldr f z (x:xs) = f x (foldr f z xs)
예를 들어 foldr (-) 54 [10,11]
동일해야합니다 (-) 10 (foldr (-) 54 [11])
, 즉, 다시 확장됩니다 (-) 10 ((-) 11 54)
. 그래서 내부 작동입니다 11 - 54
, 즉 -43; 그리고 외부 작동입니다 10 - (-43)
, 그건, 10 + 43
, 그러므로 53
당신이 관찰 한대로. 두 번째 케이스를 위해 비슷한 단계를 살펴보면 결과가 어떻게 형성되는지 알 수 있습니다!
foldr
오른쪽에서 접는 것을 의미합니다 foldr (-) 0 [1, 2, 3]
생산합니다 (1 - (2 - (3 - 0)))
. 이에 비해 foldl
생산합니다 (((0 - 1) - 2) - 3)
.
운영자가 아닌 경우 정류 foldl
그리고 foldr
다른 결과를 얻을 수 있습니다.
귀하의 경우 첫 번째 예는 확장됩니다 (10 - (11 - 54))
53을 제공합니다.
이해하기 쉬운 방법 foldr
다음과 같습니다. 모든 목록 생성자를 제공된 기능의 적용으로 대체합니다. 첫 번째 예제는 다음으로 번역됩니다.
10 - (11 - 54)
에서:
10 : (11 : [])
Haskell Wikibook에서 얻은 좋은 조언은 여기에 약간의 사용 일 수 있습니다.
일반적으로 사용해야합니다
foldr
무한하거나 접기가 데이터 구조를 구축하는 곳에서foldl'
목록이 유한 한 것으로 알려져 있고 단일 값으로 이어집니다.foldl
(진드기없이) 거의 사용되지 않아야합니다.
나는 항상 생각했다 http://foldr.com 재미있는 일러스트레이션이 되십시오. 참조 람다 궁극 게시하다.
간단한 방식으로지도, 폴드 및 폴드를 구현하면 그들이 어떻게 작동하는지 설명하는 데 도움이된다고 생각합니다. 일한 사례는 또한 우리의 이해에 도움이됩니다.
myMap f [] = []
myMap f (x:xs) = f x : myMap f xs
myFoldL f i [] = i
myFoldL f i (x:xs) = myFoldL f (f i x) xs
> tail [1,2,3,4] ==> [2,3,4]
> last [1,2,3,4] ==> 4
> head [1,2,3,4] ==> 1
> init [1,2,3,4] ==> [1,2,3]
-- where f is a function,
-- acc is an accumulator which is given initially
-- l is a list.
--
myFoldR' f acc [] = acc
myFoldR' f acc l = myFoldR' f (f acc (last l)) (init l)
myFoldR f z [] = z
myFoldR f z (x:xs) = f x (myFoldR f z xs)
> map (\x -> x/2) [12,4,10,6] ==> [6.0,2.0,5.0,3.0]
> myMap (\x -> x/2) [12,4,10,6] ==> [6.0,2.0,5.0,3.0]
> foldl (\x y -> (x+y)/2) 54 [12, 4, 10, 6] ==> 10.125
> myFoldL (\x y -> (x+y)/2) 54 [12, 4, 10, 6] ==> 10.125
foldl from above: Starting accumulator = 54
(12 + 54) / 2 = 33
(4 + 33) / 2 = 18.5
(10 + 18.5) / 2 = 14.25
(6 + 14.25) / 2 = 10.125`
> foldr (++) "5" ["1", "2", "3", "4"] ==> "12345"
> foldl (++) "5" ["1", "2", "3", "4"] ==> “51234"
> foldr (\x y -> (x+y)/2) 54 [12,4,10,6] ==> 12
> myFoldR' (\x y -> (x+y)/2) 54 [12,4,10,6] ==> 12
> myFoldR (\x y -> (x+y)/2) 54 [12,4,10,6] ==> 12
foldr from above: Starting accumulator = 54
(6 + 54) / 2 = 30
(10 + 30) / 2 = 20
(4 + 20) / 2 = 12
(12 + 12) / 2 = 12
좋아, 논쟁을 보자 :
- 반환하는 동일한 종류의 값의 목록 요소와 값 (가능한 부분 결과)을 취하는 함수;
- 빈 목록 특별 케이스에 대한 초기 결과의 사양
- 목록;
반품 값 :
- 몇 가지 최종 결과
먼저 목록의 마지막 요소와 빈 목록 결과에 함수를 적용합니다. 그런 다음이 결과와 이전 요소로 기능을 다시 얻습니다. 현재 결과와 목록의 첫 번째 요소가 최종 결과를 반환 할 때까지 앞으로 나옵니다.
요소와 이전 접기 결과를 가져 오는 함수를 사용하여 초기 결과 주변의 목록을 "접는"접히십시오. 각 요소에 대해 이것을 반복합니다. 따라서 Foldr는 목록 또는 오른쪽에서 끝까지 시작합니다.
folr f emptyresult [1,2,3,4]
로 변합니다 f(1, f(2, f(3, f(4, emptyresult) ) ) )
. 이제 평가에서 괄호를 따르십시오.
주목해야 할 중요한 것은 제공된 기능이 f
두 번째 인수는 동일한 유형을 가져야한다는 것을 의미하는 두 번째 인수로 자체 반환 값을 처리해야합니다.
원천: 내 게시물 당신이 도움이 될 수 있다고 생각하면 명령적인 자바 스크립트 관점에서 내가 그것을 보는 곳.