
Exploring Curry in Ruby
I was refactoring a method in Ruby where a boolean determined which method to call. But it didn’t just do this once, it would call the method again in a later loop. I started thinking about how to remove the duplicate code, and the idea that came to mind was “partial application”.
Partial application … because the calls are rather similar. Both methods take a parameter map as the final argument. And this parameter map was the only thing to change between calls in the loop.
My initial search turned up Proc#curry, which was introduced in 1.9.?, so should safely be available to all supported Ruby implementations. It got me curious, so I first dove into how to use curry to do what I wanted. The syntax doesn’t look idiomatic to me, but I’m OK with that if it gets the job done.
“I consider this method (Proc#curry) to be trivial and should be treated like an Easter egg for functional programming kids.”
— matz [https://www.ruby-forum.com/topic/142699#633262]
So, just to show a simple example (that works):
But I was tripped up by my own expectations. I had in mind that I would essentially have a new Proc that would take a single argument and invoke only when I called it with the last field. But underlying my calls is a Net::HTTP request. Using curry, I got errors in the curry because the HTTP request wasn’t valid.
(Note: AJAX is our internal module to wrap HTTPS calls, not a standard library.)
In other words, the GET request was being issued before I was actually ready to make my final call, which would have been:
I could be missing something here. But definitely not what I want, even if the eventual request does work.
In the end I switched to using a lambda, where I pre-feed in the fields that won’t change. Here’s what I ended up with:
And this certainly looks more idiomatic and less verbose to my eyes, without the chaining “.(*)” calls. It’d be nicer if I could trim out the extra dot from “lambda.()”, but not worth the effort for just one use case.
Another quick note. It was actually the writing of this post that made me realized that “.()” is a magic alias in Ruby for “.call()”. I’d never come across that, and it makes me wonder if there are some other magic aliases I don’t know about.