📅 May 03, 2018
👷 Chris Power
I recently stumbled across an amazing, and mind breaking method in ruby. That method is curry
. Here is the documentation for curry
from ruby 2.4’s docs.
https://ruby-doc.org/core-2.4.0/Proc.html#method-i-curry
This should look familiar to some people with knowledge of front-end javascript frameworks. Ember, for example, emphasized function currying in order to maintain a nice DDAU (Data Down Actions Up) pattern for your components. This technique also shows up in a lot of functional languages. Personally I never thought to use this sort of thing in Ruby, and I was really surprised to find that it was a part of the proc API for some time now.
let curriedFunction = function(arg) {
return function(arg2) {
return `${arg} is better than ${arg2}!`
}
}
let calledFunc = curriedFunction("peanut butter")
calledFunc("nutella")
// 'peanut butter is better than nutella!'
This is an extremely powerful concept in javascript and other functional languages. With currying, you can pass around a pre-loaded function, do some computation, and call that function with another arg that you’ve created.
Now, Ruby doesn’t have functions as first-class citizens like javascript. However, Ruby has something pretty close: Proc
. A Proc
is kind of like a function in javascript or elixir. You define it, bind it to a set of variables, and call it somewhere else.
Proc
in Ruby.Proc
): def curryable_function
->(arg1, arg2) { "#{arg1} is better than #{arg2}!" }
end
curried = curryable_function.curry(2)["peanut butter"]
curried["nutella"]
# peanut butter is better than nutella!
Now, Ruby has some syntastic oddities in it’s curry implementation. Let’s go over them.
Proc
, you can call curry(<arity>)
to curry it. The argument you pass in is the arity, or the number of args you expect total["peanut butter"]
curry()
, it gets called. in our example above, we use 2
. Meaning our Proc gets called once two args have been passed in.I think this is a very powerful tool in Ruby. Lets go over a real-life example to see it in action.
Lets say you have a class that generates an object with some information, a Game
. Depending on where this Game
is created, it needs to do some extra stuff after creation. And this ‘extra stuff’ is handled by a setup class GameSetup
.
class GameGenerator
def initialize(after_create:)
@after_create = after_create
end
def generate
game = Game.create!
after_create[game]
end
end
Then, in another class, you can generate different games:
def generate_normal_game
GameGenerator.new(after_create: setup.curry(2)["normal"]).generate
end
def generate_expert_game
GameGenerator.new(after_create: expert_setup.curry(3)["expert", previous_game]).generate
end
def setup
->(type, game) { GameSetup(type, game) }
end
def expert_setup
->(type, previous_game, new_game) { ExpertGameSetup(type, previous_game, new_game) }
end
I think this is an extremely interesting pattern. Instead of having a Generator
class explicitly asking about what it’s generating, you can pass in a callback pre-loaded with that information. Then your Generator
class doesn’t ask about itself, it just calls what was passed into it.
This also makes your top level API in the GameGenerator
class that much easier to read. You generate a game, then call whatever Proc was passed in, giving it the game
as an argument.
I am not sure if I’ll be using this pattern in the near future with Ruby. But I think it has some potential when used correctly.
We're trusted by large, medium, and small companies all over the world
Have something you're working on?
Tell Us About It