1

I have heard that R is a functional programming language, so I decided to try it out for statistical computing. I am familiar with functional programming paradigms in Scala and F#, and in each of those languages, there is a neat feature called "pattern matching" where you can do things like this:

object Matcher extends App {

  class A
  class B extends A
  class C extends A

  class D(one: A, two: A) {

    def work {
      (one, two) match {
        case (o: B, t: B) => println("B")
        case (o: B, t: C) => println("C")
        case _ =>
      }
    }
  }

  val d1 = new D(new B, new B)
  val d2 = new D(new B, new C)

  d1.work
  //B
  d2.work
  //C
}

I was wondering if R had such a feature. Pattern matching in scala and F# can get more complicated and do type checks, checks on tuples, conditional checks, and more. But whenever I do a search for "pattern matching in R," all I get are regular expression type results. Does R, a functional language, not have this feature, or do I just not know what it's called?

user3685285
  • 6,066
  • 13
  • 54
  • 95
  • 3
    I was going to say `switch`, but then I looked up [pattern matching vs switch](https://stackoverflow.com/q/199918/903061), so instead I'll say: no, I don't think R has that. Though `switch` could work for the example you give. – Gregor Thomas Oct 13 '17 at 19:27
  • 2
    @Swapnil grep* are for regular expression (ie. strictly text) pattern matching. This is a different construct: (non regular expression) pattern matching, as in this question, is a language-level feature that is often used for or involving structured decomposition of sequences/types. – user2864740 Oct 13 '17 at 19:31
  • 2
    Try the lambda.r R package on CRAN and also the book by that package's author ( https://cartesianfaith.files.wordpress.com/2013/09/rowe-modeling-data-with-functional-programming.pdf ) and relevant articles on the author's blog: ( https://cartesianfaith.com/category/functional-programming ) The rscala package on CRAN may also be of interest. – G. Grothendieck Oct 13 '17 at 19:48

2 Answers2

5

You can get some of the behavior you're after with the switch function. However, R does not have sum types like the ones you're used to in Scala and F#.

R is a dynamic language, a lot like scheme and lisp but with different syntax. You're going to have to make a few adjustments if you're coming from a strongly typed language like F# or Scala. You lose the benefits of strong types, but you gain the benefits of dynamic ones.

It turns out that for data analysis, dynamic typing is often a better fit.

Patrick Perry
  • 1,422
  • 8
  • 17
  • 3
    Common Lisp is dynamically typed - yet there are several different pattern matching implementations available. So pattern matching is not strictly a typed vs untyped divide (in a strongly typed language, among other things, it allows promotion of many type errors that might otherwise go undiscovered until run-time). Anyway, have an example and/or documentation of more advanced R-switch usage here? – user2864740 Oct 13 '17 at 20:13
  • 4
    Point taken. Most of what you do in R is vectorized, though, and pattern matching doesn't work well in those contexts. You may also want to look at the `tapply` function: split a vector of values into subsets defined by a categorical variable (a factor), then apply a function to each subset. You may also be interested in the `dplyr` or `purrr` packages. – Patrick Perry Oct 13 '17 at 20:22
2

R is... very different. To do something like that, you would use S4 Generics and Method Dispatch, which use a signature to access methods. It would essentially reproduce the behavior inside your Matcher object. Here is the sample code:

#- Typical R OO code uses the concept of Generic function dispatch. To use "work" as a
#- method, I need to set the generic function, from which all other methods will be
#- dispatched from. Normally, R does this by default, but it is always nicer to declare it
#- directly, as it shows that you *own* said generic. This is the example for S4 methods, 
#- so the dispatching might look weird at first (?).

require("methods")
setGeneric("work", function(one, two) print("Default"))

#- Now that we have a generic, we can create your classes and use method
#- dispatch to produce a similar effect to your pattern matcher.
setClass("A")
setClass("B", contains = "A")
setClass("C", contains = "A")


# Now, the equivalent for your "cases" in R...
setMethod("work", c(one = "B", two = "B"), function(one, two) print("B"))
setMethod("work", c(one = "B", two = "C"), function(one, two) print("C"))

work(new("B"), new("B"))
# B

work(new("B"), new("C"))
# C

#- Just an additional print call to make it obvious
work()
# Default

Note that I could have just as well defined it for independent classes "B" and "C", and it would have worked. Secondly, encapsulating this code inside an object as you did would be very tedious (e.g. using R6/Reference classes or something like that), and highlights the difference with R. Functions just love to live outside objects in R, and so it is easier to dispatch them with the object you intend to use them in as an additional argument for the signature, rather than placing them inside a particular object structure.