Functional ruby
Tags: ruby, functional
Published: 2020-02-20 10:32:36

Having written elixir for a while I got curious to see what all can be done in
ruby, in a functinoal way mostly in comparison to Elixir. Below are some of the
ruby methodologies that I found. I am skipping lambdas and procs for now since
they are widely discussed at many places. The snippets are self explanatory.

## Splat `*` and destructuring a list

Never knew I could deconstruct an array like this.

```
  first, *rest = [1,2,3]
  # => first == 1
  # => rest == [2,3]
```

The above led me to reimagine `#map` in a functional way.

```
arr = [1,2,3]
fn = ->(x) { |x| x*2 }

def remap(arr, fn)
  return if arr == []

  first, *rest = [1,2,3]

  first, *rest = arr
  [].push(fn.(first)).push(remap(rest, fn))
end
```

## Shorthand proc invocation

Ruby has procs and lambdas, for this post we are not digging on those two topics
much.

Creating a proc

```
double = Proc.new { |x| x*2 }
```

Creating a lambda

```
double = ->(x) { x*2 }
lambda = lambda { "Lambda" }
```

Back to the current section, you would know this:

```
def main
  [1,2,3].map(&:+)
end
```

The above snippet retruns the sum of the elements.

Let's decrypt `(&:+)`

`&` is shorthand for [to_proc](http://ruby-doc.org/core-2.0.0/Symbol.html#method-i-to_proc)

```
def to_proc
  proc { |obj, *args| obj.send(self, *args) }
end
```

`:` is just a symbol notation (Read on ruby symbols)
`+` the operator

Now essnetially, you could look at it as `& :+`, so a symbol `:+` is passed.
Now, as per the definition of to_proc the symbol is called upon the object
itself.

So if you pass a symbol, it is turned into a proc.

`Symbol#to_proc` was added to address this common pattern

```
arr.map do { |x| x.upcase }
```

This then becomes:

```
arr.map(&:upcase)
```

Now in order to create a custom functions that we can pass to map we should use
a lambda. Lambdas are essentially anonymous functions.

If you are familiar with javascript, you would have used lot of anonymous
functions for defining callbacks. On a similar anology we can proceed with a
squaring function.

```sh
irb(main):004:0> [1,2,3].map(&(->(x) { x*x}))
=> [1, 4, 9]
```

Looks cryptic but you can see that we created an anonymous function and passed
it in with `&`.

We could take it out and define the function somewhere else giving

```sh
irb(main):005:0> fn = ->(x) { x*x }
=> #<Proc:0x00007f89f19b3cf0@(irb):5 (lambda)>
irb(main):006:0> [1,2,3].map(&fn)
=> [1, 4, 9]
```

Let's take a step back now, we just discussed `&` essentially calls `#to_proc`
on it.

Another important thing to remember, if we use a symbol the corresponding method
is called on the object itself i.e

```sh
irb(main):009:0> [1,2,3].map(&:fn)
Traceback (most recent call last):
        5: from /Users/manu/.rbenv/versions/2.6.3/bin/irb:23:in `<main>'
        4: from /Users/manu/.rbenv/versions/2.6.3/bin/irb:23:in `load'
        3: from /Users/manu/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
        2: from (irb):9
        1: from (irb):9:in `map'
NoMethodError (undefined method `fn' for 1:Integer)
```

Since `Integer` doesn't have a method `fn`, it failed.

Hence,

```
irb(main):011:0> [1,2,3].map(&:odd?)
=> [true, false, true]
irb(main):012:0>
```

That's it!