The Working R Programmer

Tips and tricks for serious software development in R

pmatch 0.1.3

I have just released version 0.1.3 of pmatch to CRAN. There are not a lot of changes to this version compared to 0.1.2, but enough that I felt it would be good to get a version out before I pull the entire package apart to make it dependent on toolbox for its transformation function. Which it will be in 0.1.4, I think.

Version 0.1.3 have the following new features:

Local variable bindings

Say you have a tree defined as

Tree := Leaf(v : numeric) | Node(left : Tree, right : Tree)

Then you can get components of a tree using cases

tree <- Node(Leaf(1), Node(Leaf(2),Leaf(3)))
      Leaf(v) -> "foo",
      Node(left, right) -> "bar")
## [1] "bar"

but getting hold of the left and right subtrees as local variables is only easy with cases (or, if you are brave, you can get them as tree$left and tree$right but that is only until I change the implementation).

Now, you can assign to local variables using this notation:

bind[left, right] <- tree
## Leaf(v = 1)
## Node(left = Leaf(v = 2), right = Leaf(v = 3))

You can actually do more than that. The mechanism is good for returning more than one value from a function

double <- function(x, y) list(x = 2 * x, y = 2 * y)
bind[x,y] <- double(2,3)
c(x, y)
## [1] 4 6

and such assignments happen in parallel, so you can switch variable-values like

bind[x,y] <- c(y,x)
c(x, y)
## [1] 6 4

New cases notation

I have written about issues with byte compilation of cases calls earlier. The byte compiler does not like that we assign to literals, so

is_leaf <- function(tree) {
   cases(tree, Leaf(v) -> TRUE, Node(left, right) -> FALSE)

would give you an error.

I have now extended the syntax so you can use ~ instead of ->, and

is_leaf <- function(tree) {
   cases(tree, Leaf(v) ~ TRUE, Node(left, right) ~ FALSE)

is accepted just fine by the byte compiler (and any other static analysis programs I’ve tried).

Function rewriting

I implemented this before I extended the cases notation, but you can also transform a function to get around the byte compiler issues.

I wrote about that here so I won’t repeat it now.