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.
You can use pattern matching to test the shape and values of the data instead of transforming it into a set of objects.
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 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.
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.
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"]))
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With