2012-02-12 13 views
6

Dal momento che tutti gli esempi nella guida sono con le liste, mi riesce difficile vedere come utilizzare pattern matching in Racket di scrivere corrispondenza condizionale come OCaml fa, ad esempio:condizionale pattern matching in Racket

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

Come scriverei qualcosa di simile in Racket?

Grazie.

risposta

10

La libreria racket/match include la corrispondenza del modello che può utilizzare predicati arbitrari tramite il modello ?. Insieme a and, dovresti riuscire a far si che il matcher di Racket si comporti. Anche se sono un po 'debole nel mio OCaml, penso che la seguente traduzione del codice di cui sopra corrisponde il suo significato:

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

Il ? matcher ha un implicito and incorporato al suo interno, in modo che il codice può essere espresso un po' più succintamente:

(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 entrambi, le lambda in là non stanno a guardare cosa ma ho abbinato, quindi ho solo chiamato li _ per indicare un non fare-cura. Ma puoi immaginare schemi più sofisticati in cui i predicati potrebbero interessarsi profondamente a ciò che esattamente è stato abbinato.

Eli suggerisce di utilizzare un generale cond qui, poiché non vi è alcuna corrispondenza significativa del modello nel codice. Sono d'accordo. Il codice sarebbe simile a questo:

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

L'utilizzo di così tanti '' 'suggerisce che sarebbe espresso meglio con un semplice' cond' ... –

3

L'abbinamento di modelli può essere facilmente tradotto in una sequenza di test, non esiste una lingua in cui non sia possibile farlo.

Ciò che è eccezionale con OCaml (e probabilmente Haskell) è che il compilatore traduce il codice nella sequenza ottimale di test quando è possibile (ovvero il programma non testerà mai due volte la stessa condizione, almeno quando si evita le protezioni when).

+1

Mi aspetterei che lo stesso accada in Racket, poiché ha capablities di pattern matching esplicite, no? – GiantSquid

+1

Probabilmente è il caso se usi 'match', ma non se usi' cond'. Ma non sono esperto in Racket, solo in OCaml. –