Transforming a function that receives multiple arguments into a function that receives only one argument:
# ((a, b) -> c) -> a -> b -> c
curry = (f) ->
(a) ->
(b) ->
f(a,b)
_add = (x,y) -> x + y
add = curry _add
add(2)(3) # ==> 5
add7 = add 7
add7 10 # ==> 17
Writting pure higher order curried functions in CoffeeScript is easy and powefull:
map = (f) ->
(list) ->
return (f x for x in list)
map(add7)([1, 2, 3]) # ==> [ 9, 10, 12 ]
filter = (f) ->
(list) ->
result = []
for x in list
result.push x if f x
return result
odd = (num) -> num % 2
filter(odd)([1..10]) # ==> [ 1, 3, 5, 7, 9 ]
fold = (f) ->
(init) ->
acc = init
(list) ->
acc = f(acc)(x) for x in list
return acc
sum = fold(add)(0)
sum [1..43] # ==> 946
mult = (x) -> (y) -> x * y
product = fold(mult)(1)
factorial = (x) -> product [1...x]
factorial 6 # => 120
f : B --> C
g : A --> B
f . g : A --> C
negate = (bool) -> ! bool
odd = (num) -> num % 2
even = compose(negate)(odd)
comp = (f) ->
(g) ->
(args...) ->
return f(g.apply @, args)
head = (list) -> list[0]
tail = (list) -> list[1..]
fold1 = (fn) ->
(list) ->
fold(fn)(head list)(tail list)
compose = fold1(comp)
# Naive example
bestStudent = compose [head, (sortBy meanQualification), (filter hasPassedAllExames)]
mostCommon [1,7,200,6,3,7,7,999,1,44] # ==> 7
mostCommon 'functional programming!' # ==> 'n'
compare = (x) ->
(y) ->
return 1 if x > y
return -1 if x < y
return 0
equal = (x) -> (y) -> x is y
negate = (bool) -> ! bool
maxBy = (fn) ->
(x) ->
(y) ->
return y if fn(x)(y) is -1
return x
maximumBy = (fn) ->
fold1(maxBy(fn))
reject = (fn) ->
return filter(compose [negate, fn])
split = (fn) ->
(list) ->
fullfilled = filter(fn)(list)
rejected = reject(fn)(list)
return [fullfilled, rejected]
groupBy = (fn) ->
(list) ->
return [] unless list.length
x = head list
xs = tail list
[ys, zs] = split(fn x)(xs)
# Recursion
return [[x].concat(ys)].concat(groupBy(fn)(zs))
group = groupBy equal
group [6,7,8,6,7,8,9,1] # [ [ 6, 6 ], [ 7, 7 ], [ 8, 8 ], [ 9 ], [ 1 ] ]
length = (list) -> list.length
compareLength = (list1) ->
(list2) ->
compare(length list1)(length list2)
mostCommon = compose [head, (maximumBy compareLength), group]
mostCommon [1,7,200,6,3,7,7,999,1,44] # ==> 7
mostCommon 'functional programming' # ==> 'n'