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

About these ads