Reputation: 7183
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
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
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