Technically, Ruby doesn’t have functions, but methods. However, a Ruby method behaves almost identically to functions in other language:
def double(n)
n * 2
end
This normal method/function takes a parameter n
, doubles it and returns the value. Now let’s define a higher order function (or method):
def triple(n)
lambda {3 * n}
end
Instead of returning a number, triple
returns a method. You can test it using the Interactive Ruby Shell:
$ irb --simple-prompt
>> def double(n)
>> n * 2
>> end
=> :double
>> def triple(n)
>> lambda {3 * n}
>> end
=> :triple
>> double(2)
=> 4
>> triple(2)
=> #<Proc:0x007fd07f07bdc0@(irb):7 (lambda)>
If you want to actually get the tripled number, you need to call (or “reduce”) the lambda:
triple_two = triple(2)
triple_two.call # => 6
Or more concisely:
triple(2).call
This is not useful in terms of defining very basic functionality, but it is useful if you want to have methods/functions that are not instantly called or reduced. For example, let’s say you want to define methods that add a number by a specific number (for example add_one(2) = 3
). If you had to define a ton of these you could do:
def add_one(n)
n + 1
end
def add_two(n)
n + 2
end
However, you could also do this:
add = -> (a, b) { a + b }
add_one = add.curry.(1)
add_two = add.curry.(2)
Using lambda calculus we can say that add
is (λa.(λb.(a+b)))
. Currying is a way of partially applying add
. So add.curry.(1)
, is (λa.(λb.(a+b)))(1)
which can be reduced to (λb.(1+b))
. Partial application means that we passed one argument to add
but left the other argument to be supplied later. The output is a specialized method.
Let’s say we have really big general formula, that if we specify certain arguments to it, we can get specific formulae from it. Consider this formula:
f(x, y, z) = sin(x\\*y)*sin(y\\*z)*sin(z\\*x)