Racket中的条件模式匹配

时间:2012-02-12 21:55:55

标签: functional-programming pattern-matching ocaml racket

由于指南中的所有示例都带有列表,我发现很难看到如何在Racket中使用模式匹配来编写像OCaml那样的条件匹配,例如:

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 *)
    ...

我如何在Racket中写出类似的内容?

感谢。

2 个答案:

答案 0 :(得分:10)

racket/match库包括可以通过?模式使用任意谓词的模式匹配。与and一起,您应该能够让Racket的匹配器表现出来。虽然我的OCaml中有点弱,但我认为上面代码的以下翻译符合其含义:

(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")

?匹配器中嵌入了隐式and,因此代码可以更简洁地表达为:

(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"]))

在两者中,那里的lambdas没有看到匹配的东西,所以我只是将它们命名为_来表示不关心。但是你可以设想更复杂的模式,谓词可以深入关注究竟是什么匹配。

Eli建议在这里使用通用cond,因为代码中没有任何重要的模式匹配。我同意。代码如下所示:

(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"]))

答案 1 :(得分:3)

模式匹配可以很容易地转化为一系列测试,没有语言你不能这样做。

OCaml(可能还有Haskell)模式匹配的好处在于编译器在可能的情况下将代码转换为最佳测试序列(即程序永远不会测试两次相同的条件,至少在你避免使用时when警卫。)