我正在尝试使用Racket的“匹配”表单,并希望匹配列表中的项目序列。每个项目都有特定的属性。例如,如果我想匹配(大致)正则表达式的数字和字符串的交替序列:
#rx"([0-9]+ \"[a-zA-Z0-9]+\")+"
下面的代码似乎可以完成这项工作:
(define (match-sequence L)
(let ([n-lst '()] ; Used to collect numbers found.
[s-lst '()]) ; Used to collect strings found.
(define (m-test L)
(match L
[(list-rest (? number? n) (? string? s) ... (? m-test))
(set! n-lst `(,@n-lst ,n))
(set! s-lst `(,@s-lst ,(car s)))
(list (reverse n-lst) (reverse s-lst))]
['()
#t]
[else
#f]))
(m-test L)))
我意识到上面的#rx和代码并不完全匹配相同的序列,但它只是一个类比。
这是在Racket中最简洁的写作方法吗?
我尝试了类似的模式:
(list ((? number? n) (? string? s)) ...)
并且Racket不接受这个。
模式如: (list(?number?n)(?string?s)...) 要求匹配列表的第一项是数字,其他所有项都是字符串。
我试过quasquotation和拼接在几个方面没有成功。
必须有一个更优雅的阵型,但我似乎无法找到它。任何帮助,将不胜感激。感谢。
答案 0 :(得分:5)
看起来就像你试图将数字与其他数字分开一样,这并不困难:
(define (match-sequence L)
(match L
[(list* (? number? n) (? string? s) ... rest)
(let ([r (match-sequence rest)])
(list `(,n ,@(car r)) `(,@s ,@(cadr r))))]
['() '(() ())]))
但在这种情况下,您可以使用filter
,甚至更好,partition
:
(partition number? '(1 "a" "b" 2 3 "c" "d" 4))
但也许你想把字符串子序列组合在一起,上面的代码更接近:
(define (match-sequence L)
(match L
[(list* (? number? n) (? string? s) ... rest)
(let ([r (match-sequence rest)])
(list `(,n ,@(car r)) `(,s ,@(cadr r))))]
['() '(() ())]))
在这种情况下,使用多个值而不是组成列表包装器更容易:
(define (match-sequence L)
(match L
[(list* (? number? n) (? string? s) ... rest)
(let-values ([(ns ss) (match-sequence rest)])
(values `(,n ,@ns) `(,s ,@ss)))]
['() (values '() '())]))