What’s the problem
Here are some simple functions to use in our tests. Two are named and curried, one is anonymous.
Here’s a simple curry implementation I took from Erin Swenson-Healey’s post
Let’s make an inc function that just adds 1, then we’ll inspect it with console.log:
Riiiiigghhhht. That’s not really all that helpful. It would be lovely to see add and its argument 1 somewhere so I know what’s going on.
Let’s fix this up. The trick is to overwrite toString() and have it refer to the original function (called fx here). Then we’ll log out the args that are applied.
Here’s the important bit (I’ll show it all together when we’re finished).
In the words of daft punk, one more time:
Wow, that’s so much more helpful than displaying curry’s implementation. What if we don’t apply it at all though?
Doh! We’ll need to also overwrite f1.toString(), which will simply be fx.toString().
Great! We can inspect the actual underlying function in all cases. Now, let’s look at a slightly more complicated example:
Here, map and inc are both partially applied functions. The output is alright, but like an antique contact lens, it’s a little hard on the eyes. If we named the functions, why not show that instead?
Here’s a helper:
Now we can output a very nice inspection of the currying going down:
Here’s the improved curry in all its debuggable glory:
We can inspect functions made via compose() with the same trick.
I’ll steal a simple compose from Blake Embrey’s post. By the way, I chose these two implementations of curry and compose because they were the first search results and seemed simple enough. The ones in ramda and lodash are optimized and thus more complicated.
We end up in compose’s messy bedroom if we try to inspect our function:
That’s not very friendly. Let’s use our new favorite debugging tool: toString()
This is a little more complicated because we have to slice the arguments object and stringify each function. Let’s take it for a spin:
Since map and add are curried, they are using our previous toString(). We just output the normal toString() for head.
This approach works particularly well if we are composing other compositions — as one does in this paradigm.
It inlines our composition nicely. We can do extra fancy tricks to pretty print, but this is already a huge improvement over the opaque innards of compose.
There’s one very common error when using compose. Often times, we give it something other than a function. This typically occurs when we either forget to partially apply a function of multiple arguments or we accidentally apply a function with all its arguments.
We’ve called add with two arguments, returning a value rather than a function to compose (yes I know functions are values too…).
Let’s catch this error and throw a better message:
Let’s try this again:
Much nicer to see what’s going on here. Of course, types would prevent this in the first place, but then I’d suggest using Elm or PureScript instead of messing with any of this stuff.
We could use this to show memoized functions in a sane way. The same technique can be used to display the inner value of functors and monads as well (shown here though it should be recursive).
When I feel writey, I’m still working on the Mostly Adequate Guide if you’re into this junk. G’day.
*Artwork by Alexandria Gold http://riaartworld.tumblr.com