【问题标题】:How can I use the results of a pattern match to produce a value in a match-expander?如何使用模式匹配的结果在匹配扩展器中生成值?
【发布时间】:2015-03-15 13:34:54
【问题描述】:

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

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

【问题讨论】:

    标签: scheme pattern-matching racket


    【解决方案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")
    

    【讨论】:

      【解决方案2】:

      首先,您的pregexp 模式中有一个错字:

      (pregexp #px"^(.+)\\s(.+)\\s(.+)$" a b c)
      

      我想你想要:

      (pregexp #px"^(.+)\\s(.+)\\s(.+)$" (list _ a b c))
      

      至于你的主要目标:

      我经常发现自己在其他模式中匹配这个包含三个元素的列表,然后从中创建一个结构。因此,我想简化这个......

      好吧,您可以通过使用 app 和合适的函数来完成此操作。有趣的是,你的 foo-from-string 函数是……正是那个合适的函数。

      例如,匹配一个字符串并得到一个foo struct:

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

      【讨论】:

        猜你喜欢
        • 2016-02-08
        • 2021-12-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-27
        • 2011-07-05
        相关资源
        最近更新 更多