Well this certainly took a while but the latest installment of my functional dispatching library for R is finally released and pushed to CRAN. As a major point release, it has some breaking changes, although the older style of 1.x is supported via an option (more later).

The 2.x series of futile.paradigm introduces a cleaner syntax that doesn’t clutter the environment. All function variants are attached to a single function reference, which means multi-part definitions are much cleaner than in 1.x.

fact %when% (length(x) == 1)
fact %as% function(x) { fact(1:x) }

fact %when% (length(x) > 1)
fact %as% function(x) { prod(x) }

Adding additional guards is done by using the %also% operator.

fact %when% is.numeric(x)
fact %also% (length(x) == 1)
fact %as% function(x) { fact(1:x) }

Default function variants can now be defined in case all others fail. This only works when the argument counts match, although you’re safe if you use the ellipsis argument here.

fact %default% function(x) { fact(as.numeric(x) }

Now calling the function is exactly how you would expect. Functional polymorphism works as expected and all function variants have clear code paths, making each definition remarkably concise.

> fact(5)
[1] 120
> fact("5")
[1] 120
> fact(1:4)
[1] 24

What about optional arguments? I’ve teetered back and forth on whether this is a good idea (always deciding on no), but there are circumstances where variables should be passed along for compatibility with other dispatching systems. When this need arises, it’s easiest to simply pass in a list as an extra parameter and pass it along as necessary. Sometimes I’ll just attach() the list to the environment inside the function definition, which makes it easy to access any variables specified.

This post is a brief introduction to futile.paradigm and how to structure code in a functional way in R. There are other fun features in version 2.0 of futile.paradigm that I will discuss in later posts, but this covers the bare essentials.

Code Listing

Here’s a complete code listing for convenience.
fact %when% is.numeric(x)
fact %also% (length(x) == 1)
fact %as% function(x) { fact(1:x) }

fact %when% (length(x) > 1)
fact %as% function(x) { prod(x) }

fact %default% function(x) { fact(as.numeric(x)) }
About these ads