如何使用模式匹配的结果在匹配扩展器中生成值?

时间:2015-01-16 20:52:42

标签: scheme pattern-matching racket

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

不幸的是,由于abc在调用传递给app模式的函数时未绑定,因此失败。有没有办法实现这样的匹配扩展器,以便它可以对匹配的值执行一些任意的过程?

2 个答案:

答案 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")