I went through LYAH, and it gave me a great appreciation for the programming language and functional programming style in general. Two things I really like are partial function application and pattern matching. If Ruby had these features, how could they be used in a Rails app?
I’ve been learning Rails for about a month now. I’m sure my ‘before’ code could be improved markedly.
My Rails app has a lot of related data objects, and I find that I’m adding new relations fairly regularly. Artist
s have many Release
s through Contribution
s, Release
s have many ReleaseDate
s, User
s follow many Artist
s, etc. As such, I’ve got methods like will eventually look like this:
Pattern matching would mostly be nice as a way to make the code more concise. If Ruby had it, it might look like:
The pattern_match
function would take an expression and a hash of results paired with lambdas and execute the expression corresponding with the result. The return value of the pattern_match
function is the return of the lambda that gets executed.
The above code, in my opinion, looks quite a bit cleaner, and allows a bit more modularity than the former. It can be refactored like so:
Mathematicians have determined that any function with multiple arguments can be expressed as a series of functions that take a single argument, return a function that takes a single argument, etc. until all arguments have been used and then returns the final result. In Haskell, this means that you can define a function: func x y z = x + y + z
that takes three arguments and sums them. You can further define a function func' = func 1
. func'
is a function that takes two arguments, sums them, and adds 1. The func
function has been partially applied. func'' = func' 2
partially applies func'
with the argument 2, which means that func''
is now a function that takes a single argument and adds 3 to it. The following code snippet illustrates what is happening:
That’s all fine, but it seems really abstract and kind of weird and confusing. Why would you want to do that?
Going back to my add_X
method above, even with the pattern_match
function defined, there is a lot of code repetition between models. They’re all essentially doing the same thing: Receiving an object, pattern matching the object, and responding to the type of object. The specifics are different, but could it be abstracted out? With partial function application, it would be fairly easy. The method body would look something like:
In languages with partially applied functions, the parameters that aren’t likely to change much are assigned first, and the parameters that change frequently are listed later. Each class would want to partially apply the method starting with the base class, then specify the relations, and then specify the matching function.
With this sort of setup, every class in my application is reusing the same basic code for the creation of releases. All they’re doing is customizing the methods to be more and more specific, until it eventually does what’s wanted. Since everything is so broken up, a rather thorough testing of the base methods will practically ensure that the methods that build upon it have little to go wrong. Naturally, this sort of thing is much more powerful in a language with a powerful type system and restricted side-effects, but it’s not strictly theoretical.
(Yes, you could just explicitly pass all parameters to that initial method, but that’s not as fun!)