Понимание различных сгибателей

Я понимаю простые фолд-заявления вроде

foldr (+) 0 [1,2,3]

Однако у меня возникли проблемы с более сложными инструкциями foldr, а именно с теми, которые принимают 2 параметра в функции, и с / и - вычислениями. Может ли кто-нибудь объяснить шаги, которые происходят, чтобы получить эти ответы?

foldr (\x y -> (x+y)*2) 2 [1,3] = 22

foldr (/) 2 [8,12,24,4] = 8.0

Благодарю.

3 ответа

Решение

foldr Функция определяется следующим образом:

foldr :: (a -> b -> b) -> b -> [a] -> b
foldr _ a []     = a
foldr f a (x:xs) = f x (foldr f a xs)

Теперь рассмотрим следующее выражение:

foldr (\x y -> (x + y) * 2) 2 [1,3]

Мы дадим имя лямбде:

f x y = (x + y) * 2

Следовательно:

foldr f 2 [1,3]
-- is
f 1 (foldr f 2 [3])
-- is
f 1 (f 3 (foldr f 2 []))
-- is
f 1 (f 3 2)
-- is
f 1 10
-- is
22

Так же:

foldr (/) 2 [8,12,24,4]
-- is
8 / (foldr (/) 2 [12,24,4])
-- is
8 / (12 / (foldr (/) 2 [24,4]))
-- is
8 / (12 / (24 / (foldr (/) 2 [4])))
-- is
8 / (12 / (24 / (4 / (foldr (/) 2 []))))
-- is
8 / (12 / (24 / (4 / 2)))
-- is
8 / (12 / (24 / 2.0))
-- is
8 / (12 / 12.0)
-- is
8 / 1.0
-- is
8.0

Надеюсь, что это помогло.

Аргумент функции сгиба всегда принимает два аргумента. (+) а также (/) являются бинарными функциями так же, как в вашем втором примере.

Prelude> :t (+)
(+) :: Num a => a -> a -> a

Если мы перефразируем второй пример как

foldr f 2 [1,3]
    where
    f x y = (x+y)*2

мы можем расширить правильную складку, используя точно такую ​​же схему, которую мы использовали бы для (+):

foldr f 2 [1,3]
foldr f 2 (1 : 3 : [])
1 `f` foldr f 2 (3 : [])
1 `f` (3 `f` foldr f 2 [])
1 `f` (3 `f` 2)
1 `f` 10
22

Стоит отметить, что foldr является правоассоциативным, что показывает, как гнездятся скобки. Наоборот, foldlи его полезный кузен foldl', левоассоциативны.

Вы можете думать о foldr, maybe, а также either как функции, которые заменяют конструкторы данных их соответствующих типов функциями и / или значениями по вашему выбору:

data Maybe a = Nothing | Just a

maybe :: b -> (a -> b) -> Maybe a -> b
maybe  nothing _just Nothing  = nothing
maybe _nothing  just (Just a) = just a

data Either a b = Left a | Right b

either :: (a -> c) -> (b -> c) -> Either a b -> c
either  left _right (Left  a) = left  a
either _left  right (Right b) = right b

data List a = Cons a (List a) | Empty

foldr :: (a -> b -> b) -> b -> List a -> b
foldr cons empty = loop
  where loop (Cons a as) = cons a (loop as)
        loop Empty       = empty

В общем, вам не нужно думать о рекурсии, просто подумайте о том, что она заменяет конструкторы данных:

foldr f nil (1 : (2 : (3 : []))) == (1 `f` (2 `f` (3 `f` nil)))
Другие вопросы по тегам