foldr
определяет семейство уравнений,
foldr g n [] = n
foldr g n [x] = g x (foldr g n []) = <b>g</b> x n
foldr g n [x,y] = g x (foldr g n [y]) = <b>g</b> x (<b>g</b> y n)
foldr g n [x,y,z] = g x (foldr g n [y,z]) = <b>g</b> x (<b>g</b> y (<b>g</b> z n))
----- r ---------
и так далее.g
- это функция редуктор ,
g x r = ....
, принимающая как x
элемент списка ввода, и как r
r результат r эвристическая обработка r est списка ввода (как видно из уравнений).
map
, с другой стороны, определяет семействоуравнений
map f [] = []
map f [x] = [f x] = (:) (f x) [] = <b>((:) . f)</b> x []
map f [x,y] = [f x, f y] = <b>((:) . f)</b> x (<b>((:) . f)</b> y [])
map f [x,y,z] = [f x, f y, f z] = <b>((:) . f)</b> x (<b>((:) . f)</b> y (<b>((:) . f)</b> z []))
= (:) (f x) ( (:) (f y) ( (:) (f z) []))
Два семейства просто точно совпадают с
g = ((:) . f) = (\x -> (:) (f x)) = (\x r -> f x : r)
и n = []
, и, таким образом,
foldr ((:) . f) [] xs == map f xs
Мы можем доказать этострого по математической индукции по длине списка ввода, следуя определяющим законам foldr
,
foldr g n [] = []
foldr g n (x:xs) = g x (foldr g n xs)
, которые являются основой для уравнений в верхней части этого поста.
Современный Haskell имеет класс типа Fodable
с базовым fold
в соответствии с законами
fold<sub>(<>,n)</sub> [] = n
fold<sub>(<>,n)</sub> (<b>xs</b> ++ <b>ys</b>) = fold<sub>(<>,n)</sub> <b>xs</b> <> fold<sub>(<>,n)</sub> <b>ys</b>
, а map
естественно определяется в его терминах как
map f xs = foldMap (\x -> [f x]) xs
превращение [x, y, z, ...]
в [f x] ++ [f y] ++ [f z] ++ ...
, поскольку для списков (<>) == (++)
.Это следует из эквивалентности
f x : ys == [f x] ++ ys
Это также позволяет нам легко определить filter
по тем же линиям, что и
filter p xs = foldMap (\x -> [x | p x]) xs
По вашему конкретному вопросу расширение верно, за исключением того, что (*2 x)
должно быть записано как ((*2) x)
, что совпадает с (x * 2)
.(* 2 x)
не является допустимым Haskell (хотя действительный Lisp :)).
Функции типа (*2)
известны как " операторные секции " - отсутствующий аргумент помещается в пустой слот: (* 2) 3 = (3 * 2) = (3 *) 2 = (*) 3 2
.
Вы также попросили некоторыессылки: см. например это , это и это .