Wednesday, August 05, 2015

Using Ruby to Inject you a Monoid

A monoid has an append operation (like plus) and an identity (like 0) and you get for free a concat operation.

In Ruby it's something like:

[1,2,3].inject(0) {|a, x| a + x }
=> 6

Or just, [1,2,3].inject(:+)

In Haskell, you can even see it in the type signature for Monoid:
mconcat :: [a] -> a

You can see the array on the left ([1,2,3]) and the result unpacked (just 6).

What if you want to take it up one level of abstraction and have any operations on your list of numbers.  You just use a different monoid called Endo.

To take it to this next level you need a more abstract append and identity.  

Append needs to combine two operations:
compose = -> (f,g,*args) { f.call(g.call(*args)) }

And identity just returns what you give it:
id = -> (x) { x }

Which lets you then write:
[->(x){x + 2}, ->(x){x * 7} ].inject(id) {|x, y| compose(x, y) }.call(8)
=> 58

Or in Haskell:
Prelude> let a = foldr (.) id [(+2), (*7)]
Prelude> a 8
58

See: