在racket/match
模式中,我想匹配一些值,然后创建一个包装它们的结构。例如,采用以下(人为的)代码:
(struct foo (a b c))
(define (foo-from-string str)
(match str
[(pregexp #px"^(.+)\\s(.+)\\s(.+)$" (list _ a b c))
(foo a b c)]
[_ #f]))
我经常发现自己在其他模式中匹配这三个元素的列表,然后从中创建一个结构。因此,我想通过编写自定义匹配扩展器来简化这一过程。理想情况下,它会像这样工作:
(struct foo (a b c))
(define (foo-from-str str)
(match str
[(foo-string value) value]
[_ #f]))
也就是说,它应该自动匹配满足正则表达式的字符串,然后在成功时将值存储到foo
结构中并将其绑定到value
。我尝试写下面的内容来实现这个:
(define-match-expander foo-string
(λ (stx)
(syntax-case stx ()
[(_ result)
#'(and (pregexp #px"^(.+)\\s(.+)\\s(.+)$" (list _ a b c))
(app (λ (v) (foo a b c)) result))])))
不幸的是,由于a
,b
和c
在调用传递给app
模式的函数时未绑定,因此失败。有没有办法实现这样的匹配扩展器,以便它可以对匹配的值执行一些任意的过程?
答案 0 :(得分:1)
首先,您的pregexp
模式中存在拼写错误:
(pregexp #px"^(.+)\\s(.+)\\s(.+)$" a b c)
我想你想要:
(pregexp #px"^(.+)\\s(.+)\\s(.+)$" (list _ a b c))
至于你的主要目标:
我经常发现自己在其他模式中匹配这三个元素的列表,然后从中创建一个结构。因此,我想简化这个....
嗯,您可以使用app
和合适的函数来完成此操作。有趣的是,您的foo-from-string
函数正是......恰好适合的函数。
例如,要匹配字符串并获取foo
结构:
(match "a b c"
[(app foo-from-string x) x])
;;=> (foo "a" "b" "c")
要匹配字符串并获取foo
字段,请提供foo
结构模式:
(match "a b c"
[(app foo-from-string (foo a b c)) (list a b c)])
;;=> '("a" "b" "c")
诚然,我没有回答你关于匹配扩展器的问题,因为我不太了解它们。所以相反,我建议你可能不需要它们?
更新:实际上,这似乎也是匹配扩展器的答案:
(define-match-expander foo-string
(λ (stx)
(syntax-case stx ()
[(_ x)
#'(app foo-from-string x)])))
答案 1 :(得分:1)
是的,app
正是您想要的。您只需要在app
中执行更多操作。
#lang racket
(struct foo (a b c) #:transparent)
(define-match-expander foo-string
(λ (stx)
(syntax-case stx ()
[(_ result)
#'(app (λ (v) (apply (λ (_ a b c) (foo a b c))
(regexp-match #px"^(.+)\\s(.+)\\s(.+)$" v)))
result)])))
(define (foo-from-str str)
(match str
[(foo-string value) value]
[_ #f]))
(foo-from-str "1 2 3")