I’m pleased to announce that lambda.r 1.1.1 is now available on CRAN. This release is mostly a bug fix release, although a few important enhancements were included.
- [bug] Support Function in every type position (only supported for return type)
- [bug] Auto-replacing a function with 0 arguments fails
- [bug] Fix type inheritance
- [new] Functions that return non-scalar values work as default values on arguments
- [new] Support pattern matching on NULL and NA
- [new] Support pattern matching on special symbol EMPTY
Pattern Matching for NA and NULL
Most significantly are improvements to the pattern matching semantics. Pattern matching now supports NA and NULL directly. This is particularly useful for programmatic control when a specific function signature is required but the argument value is non-deterministic. This can happen when accessing non-existent list elements as well. Suppose you want to forecast a time series. You want to choose the forecasting method based on whether the data is seasonal or not. A classification technique is used for this purpose and sets the period or NULL if it is not seasonal.
Traditional imperative code would run the classification, check its output and then use a conditional to execute the seasonal or non-seasonal forecasting routine. A functional approach would use function clauses to control the flow.
forecast_ts(x, NULL) %as% { # non-seasonal forecast } forecast_ts(x, period) %as% { # seasonal forecast } period <- classify_ts(x) # NULL or numeric forecast_ts(x, period)
Obviously the same thing can be accomplished using an explicit guard statement, but pattern matching has an elegant simplicity to it that efficiently communicates the intent of the logic.
Behind the scenes these are additional parse transforms that take into consideration the special nature of these constants (and how you test for them). At some point I want to generalize the parse transform machinery so anyone can develop their own set of transforms (just like in erlang).
Introducing the EMPTY Pattern
I’ve also introduced a new constant called EMPTY, which allows you to pattern match on empty lists and vectors (or anything with 0 length). This means recursive definitions and other iterative methods against vectors and lists work as expected.
fold(f, EMPTY, acc) %as% acc fold(f, x, acc) %as% { fold(f, x[-1], f(x[[1]], acc)) } plus(x,y) %as% { x + y } x <- 2 n <- 0:10 fold(plus, x^n/factorial(n), 0)
You can also capture situations where empty sets are the result of set operations using EMPTY. The clean declarative aspect of this notation makes your analytical code easier to understand by removing the overhead of data management and manipulation.
Full details and source are available at: https://github.com/muxspace/lambda.r
Dear Brian,
your package looks very interesting. I am exploring the feasibility of functional programming with R, do you have any real world examples of using lambda.r in combination with usual data structures like data.frames or data.tables, that you can share?
LikeLike
Marco,
Lambda.r is designed to be fully compatible with S3 data types. Regarding real world examples, I’m currently building out an event-driven analytics and forecasting platform with lambda.r in the retail banking space. I can’t share anything at the moment, but I plan to post some articles in the future. I would suggest that you look at the unit tests in the source (inst/unitTests/) for usage ideas. I’ve also updated my other packages (e.g. tawny, futile.*) to use lambda.r, so all the source code there have good examples. Feel free to ping me if you have specific questions.
Warm Regards,
Brian
LikeLike