daj
daj

Reputation: 7183

haskell style pattern matching of parameter values for function calls in R

In R, is it possible to do function pattern matching based on parameter values ala Haskell?

i.e. if parameter x is ='foo', run one version of a function, if x is 'bar', run another version? Obviously this could be done with if statements if necessary, but I'd like to know if there's a more 'functional' approach to it.

For example, to do this kind of function selection (foo1 vs. foo2) automatically without the ifelse statement to do the conditioning:

foo1 <- function(a) {
    paste0(a, 'foo1')
}

foo2 <- function(a) {
    paste0('baz', a, 'foo2')
}

x <- 'barp'
value <- ifelse(x == 'barp', foo1(x), foo2(x))

Upvotes: 1

Views: 195

Answers (2)

chi
chi

Reputation: 116174

For general algebraic data types, you can define your own matching function helpers. These are sometimes called "eliminators", and essentially convert your ADT values into their Church encoding.

For instance, let's translate this Haskell code snipppet:

x = Just 3
y = Nothing
a = case x of Nothing -> 42 ; Just w -> w+100
b = case y of Nothing -> 42 ; Just w -> w+100

The result is:

# eliminator
matchMaybe <- function(x,kn,kj) {
   ifelse(x[[1]]=='Nothing', kn(), kj(x[[2]]))
}

# tests
x <- list('Just', 3)
y <- list('Nothing')
a <- matchMaybe(x
               ,function() { 42 }
               ,function(w){ w+100 })
b <- matchMaybe(y
               ,function() { 42 }
               ,function(w){ w+100 })

Note, however, that deep pattern matching is hard to translate in this way. That is, in Haskell you can do stuff like

case x of Just 10 -> 22 ; Nothing -> 42 ; Just w -> w+100

wherein you match the Just constructor and the inner 10 at the same time. This can not be encoded in a convenient way.

For strings, as in the OP example, a possible eliminator could be:

match <- function(x,v,kt,ke) {
   ifelse(x==v, kt(),ke(x))
}

r <- match('foo'
     , 'bar', function() { "then" }
     ,        function(x) { "else" })

Also keep in mind that I am not fluent in R, so there might be a much better approach.

Upvotes: 1

BrodieG
BrodieG

Reputation: 52677

This can be done based on the "class" of the object, but not the value. I am not super familiar with Haskell, but I though Haskell also dispatches on class/type rather than actual value? Here is the R implementation:

> foo <- function(a) UseMethod("foo")
> foo.1 <- function(a) paste(a, 'foo1')
> foo.2 <- function(a) paste('baz', a, 'foo2')
> 
> obj_1 <- structure("hello world", class="1")
> obj_2 <- structure("hello world", class="2")
> 
> foo(obj_1)
[1] "hello world foo1"
> foo(obj_2)
[1] "baz hello world foo2"

This will only dispatch based on the class of the first argument. You can use S4 methods if you want to dispatch based on multiple arguments.

Upvotes: 1

Related Questions