Берёшь модно выглядящий ЯП, например coffeescript, пишешь:
size = (xs) -> xs.length
concat = (xs) -> (ys) -> xs.concat(ys)
map = (f) -> (xs) ->
[y, ys...] = xs
if (size xs)
(concat [f y]) ((map f) ys)
else
[]
Пробуешь:
coffee> (map (x) -> x * 2) [1..5]
[ 2, 4, 6, 8, 10 ]
Потом пишешь filter:
filter = (f) -> (xs) ->
[y, ys...] = xs
if not (size xs)
[]
else if (f y)
(concat [y]) ((filter f) ys)
else
(filter f) ys
Пробуешь:
coffee> filter((x) -> x > 5) [1..10]
[ 6, 7, 8, 9, 10 ]
Теперь ты знаешь ФП лучше среднего хаскелиста и лиспера лора!
А ещё благодаря такому подходу легко можно реализовать модные сейчас трансдьюсеры:
transduce = (fns) -> (xs) ->
[f, fs...] = fns
if (size fns)
(transduce fs)(f xs)
else
xs
Использование:
coffee> transduce([(map (x) -> x * 2), (filter (x) -> x < 10), (map (x) -> x ** 2)]) [1..10]
[ 4, 16, 36, 64 ]
Свёртки:
reduce = (f) -> (xs) -> (m) ->
[y, ys...] = xs
if (size xs)
((reduce f) ys)((f y) m)
else
m
coffee> reduce((x) -> (y) -> x + y)([1..10])(0)
55
reverse = (xs) ->
aux = (m) -> (ys) ->
[z, zs...] = ys
if (size ys)
(aux (concat([z]) m)) zs
else
m
(aux []) xs
coffee> reverse [1..5]
[ 5, 4, 3, 2, 1 ]
reducer = (r) -> (m) -> ((f) -> (xs) -> r(f)(xs)(m))
reduceLeft = (f) -> (xs) -> (m) -> transduce([reverse, reducer(reduce)(m)(f)])(xs)
coffee> reduceLeft((x) -> (m) -> x + m)([1..10])(0)
55
reducer нужен для того чтобы reduce(Left) имел интерфейс трансдьюсера (как у map и filter вызванные с функцией, и собственно transduce).
update: Самое главное не забывать называть переменные f, xs, x и тд.
update 2: И да, легко получить RangeError: Maximum call stack size exceededю
update 3: Превратил однострочники в многострочникию