2016-07-03 5 views
1

Я понимаю определения foldl, foldr, но у меня проблемы с функциями, определенными ими.Определить функции с foldl foldr

Например карта с foldr:

map f []  = [] 
map f l = foldr (\x xs -> f x : xs) [] l 

Я не понимаю (\x xs -> f x : xs). Это функция отображения, которую занимает foldr? Но не должно быть (\x xs -> f x : f xs), потому что map f (x:xs) = f x : map f xs?

Пример с foldl:

concat (x:xs) = x ++ concat xs 

concat' xs = foldl (++) [] xs 
concat'' xs = foldl (\ys y -> ys ++ y) [] xs 

Конечно, я понимаю (++), но что логика (\ys y -> ys ++ y)? Это ys = [] и y = xs? Таким образом, функция принимает [] как ys и y является первым элементом xs и составляет [] с y? Конкретный пример:

concat'' [1,2,3] = foldl (\ys y -> ys ++ y) [] [1,2,3] 
=> foldl (\ys y -> ys ++ y) ((\ys y -> ys ++ y) [] [1]) [2,3] 
=> foldl (\ys y -> ys ++ y) [1] [2,3] 
=> foldl (\ys y -> ys ++ y) ((\ys y -> ys ++ y) [1] [2]) [3] 
=> foldl (\ys y -> ys ++ y) [1,2] [3] 
=> foldl (\ys y -> ys ++ y) ((\ys y -> ys ++ y) [1,2] [3]) [] 
=> foldl (\ys y -> ys ++ y) [1,2,3] [] 
=> [1,2,3] 

Другое дело: concat занимает всего 1 список xs, так что если я хочу Concat 2 списка?

concat (x:xs) ys = x ++ concat xs ys 
concat [1,2,3] [4,5,6] with foldl? 

Реверс:

reverse (x:xs) = reverse xs ++ [x] 

reverse' l = foldl (\xs x -> [x] : xs) [] l 
reverse'' l = foldr (\x xs -> xs ++ [x]) [] l 

foldr интуитивно понятно (с вопросами из выше), но то, что за обратным порядком в foldl (\xs x -> [x] : xs)? Это будет foldl (\x xs -> xs ++ [x]) [] l, не так ли?

Большое спасибо!

+1

вот пара вопросов - для первого заметим, что 'xs' re уже * был * отображен на 'f' (посмотрите на определение' foldr', чтобы понять, почему) (также 'f xs' не был бы хорошо напечатан, так как у вас был' f :: a -> b' и на в то же время 'f :: [a] -> b'', поэтому вам нужно будет идентифицировать' a ~ [a] ') – Carsten

+0

Обратите внимание, что' foldr fz [x1, x2, x3] = f x1 (f x2 (f x3 z)), поэтому 'xs' уже был сопоставлен' f'. – Bakuriu

+0

для второго: просто отметьте, что 'foldl' будет * loop * через' xs' слева (снова посмотрите на определение) – Carsten

ответ

2

Код

foldr (\x xs -> ...) end list 

можно прочитать, грубо говоря, следующим

  • сканировать весь list
  • , если он пустой, просто вернуть конец end
  • иначе:
    • пусть x быть элемент под рукой
    • пусть xs будет остальная часть списка, после того, как были обработаны
    • применить операцию ...

подчеркнутая часть имеет решающее значение. xsне остальная часть списка, но результат «рекурсивного вызова» на нем.

Действительно, xs является плохим именем для этого. В общем случае это даже не список! Например.один никогда не будет писать (глупый пример)

foldr (\x xs -> x + xs) 0 [1..100] -- sum 1..100 

а предпочитают что-то вроде

foldr (\x partialSum -> x + partialSum) 0 [1..100] -- sum 1..100 

(На самом деле, один не просуммировать с помощью foldr, но давайте оставим это в стороне.)

Итак, просто прочитайте его так:

map f l = foldr (\x mappedTail -> f x : mappedTail) [] l 
+0

Спасибо! Думаю, я понимаю склад. Карта с складкой была бы такой? 'map f l = foldl (\ x xs -> x: f xs) [] l' Итак,' x' - отображаемая часть, а 'xs' отображается? – user22709

+0

@ user22709 Морально да, но обратите внимание, что в этом случае 'x' является (сопоставленным) списком, а' xs' является элементом, поэтому он должен быть 'foldl (\ x xs -> x ++ [f xs]) [ ] list' – chi

+0

Спасибо! У вас есть предложение для более элегантного способа написать это, потому что xs - это, как правило, остальная часть списка, что здесь не так ... – user22709

 Смежные вопросы

  • Нет связанных вопросов^_^