Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditional pattern matching in Racket

Since all the examples in the guide are with lists, I find it difficult to see how to use pattern matching in Racket to write conditional matching like OCaml does, for example:

read ~var_a var_b s = match s.[0] with
    | _ when var_b >= var_a + 4 ->
        (* Do something *)
    | "a" when is_negative var_b -> 
        (* Do something else *)
    ...

How would I write something similar in Racket?

Thanks.

like image 436
Sergi Mansilla Avatar asked Feb 12 '12 21:02

Sergi Mansilla


People also ask

What pattern matching allows us?

You can use pattern matching to test the shape and values of the data instead of transforming it into a set of objects.

What is typed racket?

Typed Racket is Racket's gradually-typed sister language which allows the incremental addition of statically-checked type annotations. This guide is intended for programmers familiar with Racket. For an introduction to Racket, see The Racket Guide. For the precise details, also see The Typed Racket Reference.

What is pattern matching in programming?

What Does Pattern Matching Mean? Pattern matching in computer science is the checking and locating of specific sequences of data of some pattern among raw data or a sequence of tokens. Unlike pattern recognition, the match has to be exact in the case of pattern matching.

What is pattern matching in Haskell?

Pattern matching consists of specifying patterns to which some data should conform and then checking to see if it does and deconstructing the data according to those patterns. When defining functions, you can define separate function bodies for different patterns.


2 Answers

The racket/match library includes pattern matching that can use arbitrary predicates through the ? pattern. Along with and, you should be able to get Racket's matcher to behave. Although I'm a little weak in my OCaml, I think the following translation of the code above matches its meaning:

(define (my-read #:var-a var-a var-b s)
  (match (string-ref s 0)
    [(and _
          (? (lambda (_)
               (>= var-b (+ var-a 4)))))
     "do something"]
    [(and '#\a
          (? (lambda (_)
               (< var-b 0))))
     "do something else"]))

;; Exercising the first case:     
(my-read #:var-a 50
         60 "blah")

;; Exercising the second case:
(my-read #:var-a 50
         -40 "alphabet")

The ? matcher has an implicit and embedded within it, so the code can be expressed slightly more succinctly as:

(define (my-read #:var-a var-a var-b s) 
  (match (string-ref s 0)
    [(? (lambda (_)
          (>= var-b (+ var-a 4))))
     "do something"]
    [(? (lambda (_)
          (< var-b 0))
        #\a)
     "do something else"]))

In both, the lambdas in there aren't watching what got matched, so I just named them _ to denote a don't-care. But you can imagine more sophisticated patterns where the predicates could care deeply about what exactly got matched.

Eli suggests using a general cond here, since there isn't any significant pattern matching in the code. I agree. The code would look like this:

(define (my-read #:var-a var-a var-b s) 
  (cond
    [(>= var-b (+ var-a 4))
     "do something"]
    [(and (char=? (string-ref s 0) #\a)
          (< var-b 0))
     "do something else"]))
like image 100
dyoo Avatar answered Sep 20 '22 10:09

dyoo


Pattern-matching can easily be translated into a sequence of tests, there is no language where you cannot do that.

What's great with OCaml (and probably Haskell) pattern-matching is that the compiler translates the code into the optimal sequence of tests when it is possible (i.e. the program will never test twice the same condition, at least when you avoid the when guards).

like image 33
Fabrice Le Fessant Avatar answered Sep 21 '22 10:09

Fabrice Le Fessant