如何使宏与`match`一起使用?

别尔泽比尔斯克

我正在尝试为使用制作的计算器编写某种类似于有限状态机的东西racket/gui,因此我决定使用casematch实现它。对于特定的状态和符号,我将执行一些任意代码并返回机器的下一个状态。一个简单的例子:

  (case current-state
    [(state-1)
     (match symbol
       [(? predicate-1?) 
        (some-action)
        next-state]
       [(? predicate-2?) 
        (some-action)
        next-state]
       ; ...
       )]
    ; ...
    )

不过,我想使它更易于阅读,并想通过宏来玩弄。我经常使用某些谓词,并希望以较短的方式编写它们。而且我不喜欢在一系列操作结束时丢失下一个状态。我想要这些信息放在首位。所以我更喜欢写这样的东西:

(case current-state
  [(state-1)
   (match symbol
     [:PRED-1: next-state
      (some-action)]
     [:PRED-2: next-state
      (some-action)]
     ; ...
     )]
  ; ...
  )

我对宏的使用不太了解,而我的早期尝试都变得很糟糕。我的第一个部分尝试只是谓词宏。这是一个简单的例子:

(define (in-list value lst)
  (if (list? (member value lst))
    #true
    #false))
(define (is-non-zero-digit? symbol)
  (in-list symbol '(1 2 3 4 5 6 7 8 9)))
(define-syntax :NOT-0:
  #'(? is-non-zero-digit?))

(match 0
  [:NOT-0: 'wrong]
  [_ 'right])
; 'wrong

我不确定为什么会这样。我认为:NOT-0:会扩展到(? is-non-zero-digit?)我尝试的另一件事是通过定义名为的宏来获得所需的顺序transition

; defined earlier in file
(define-syntax-rule
  (transition pattern next-state action ...)
  [pattern action ... next-state])
; ...
; the below is from a rackunit test
(define a-variable 0)
(define (side-effect)
  (set! a-variable 1))
(define result
  (match 0
    (transition (? is-non-zero-digit?) 'wrong (side-effect))
    [_ 'right]))
(check-equal? result 'right)
(check-equal? a-variable 1))

但是我得到了错误state-machine.rkt:220:21: ?: unbound identifier我希望得到答案,以便为我提供一种获取所需表格的方式,并且希望您能解释一下为什么我以前的尝试没有奏效。

Sorawee Porncharoenwase

让我们先说说为什么你:NOT-0:不工作。首先,宏是语法对象转换器。即,从语法对象到语法对象的功能。所以你需要写:

(define-syntax :NOT-0:
  (lambda (stx) #'(? is-non-zero-digit?)))

或使用其简写形式:

(define-syntax (:NOT-0: stx)
  #'(? is-non-zero-digit?))

但是更正后的代码也不起作用。原因是Racket宏默认情况下是“从外向内”扩展的。这意味着:

(define-syntax-rule (foo (#:foo x))
  x)

(define-syntax-rule (bar x)
  (#:foo x))

(foo (bar 1)) ; doesn't work, because `foo` is expanded first, and it couldn't find #:foo

希望让用户大多数宏扩展其功能,例如foo将提供“宏定义宏”,你可以用它来定义bar在一个方式foo了解到,bar首先应该扩大。有关技术细节,请参见Matthew Flatt等人的可协同工作的宏

对于您的特定问题,Racketmatch提供define-match-expander了一个宏,它定义了我上面描述的宏。您可以像这样使用它:

(define-match-expander :NOT-0:
  ;; can also use syntax-case on stx to further ensure that stx must have a particular shape.
  (lambda (stx) #'(? is-non-zero-digit?)))

(define (is-non-zero-digit? symbol)
  ;; no need to define in-list. member alone would suffice
  (member symbol '(1 2 3 4 5 6 7 8 9)))

(match 0
  [(:NOT-0:) 'wrong]
  [_ 'right])

请注意,您需要在周围加上括号:NOT-0:如果您有裸露的:NOT-0:match请将其视为绑定匹配值的标识符。


就个人而言,我认为球拍match在这里不合适。通常,当有很多(? predicate)子句时,建议您将其转换为cond

(cond
  [(predicate-1? symbol) ...]
  [(predicate-2? symbol) ...]
  ...)

最后,match如果您确实希望它以所需的形式出现,则可以创建自己的表单。然后,您可以根据需要扩展matchcond或球拍match另外,您将完全控制其中的子表单,从而可以交换“动作”和“状态”。这是一个小例子。

(define-syntax-rule (match e [pred e*] ... [#:else e-else])
  (let ([v e]) ; so that we evaluate e only once
    (cond [(pred v) e*] ... [else e-else])))

(match 0
  [is-non-zero-digit? 'wrong]
  [#:else 'right])

(require (only-in racket/match [match r:match]))
;; Racket's match is still available via r:match

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何定义与结构数组C一起使用的宏

来自分类Dev

如何将valgrind与实际上是宏扩展的函数一起使用

来自分类Dev

如何确定将_IONBF宏与setvbuf函数一起使用,文件操作速度很慢

来自分类Dev

如何在Spring MVC中将宏与FreeMarker一起使用

来自分类Dev

如何获取Scala命名和默认参数以与宏一起使用

来自分类Dev

气流宏可以与CloudSqlInstanceExportOperator一起使用吗?

来自分类Dev

将宏container_of与struct成员一起使用

来自分类Dev

如何在计算机上创建可与任何Excel工作簿一起使用的Excel宏?

来自分类Dev

如何将INDEX(MATCH())与重复值一起使用

来自分类Dev

如何编写此正则表达式以与 preg_match 一起使用?

来自分类Dev

如何使 INDEX 和 MATCH 与 VBA 中的文本一起使用?

来自分类Dev

如何使PreferenceFragment与MainActivity一起使用

来自分类Dev

如何与默认包装一起使用?

来自分类Dev

backpatching如何与标记一起使用?

来自分类Dev

getline如何与cin一起使用?

来自分类Dev

如何使Powermock与Dexmaker一起使用

来自分类Dev

如何使__debugInfo与XDebug一起使用?

来自分类Dev

如何与gradle一起使用JMH?

来自分类Dev

如何使TLS与Java一起使用?

来自分类Dev

如何与JTextArea一起使用JScrollPane?

来自分类Dev

如何与流星一起使用Prerenderio?

来自分类Dev

如何与Eclipse一起使用TortoiseSVN

来自分类Dev

如何与[if]一起使用[getElementById]?

来自分类Dev

如何使Mixitup与Wordpress一起使用?

来自分类Dev

如何使bbmustache与Elixir一起使用?

来自分类Dev

RESTful如何与PHP一起使用?

来自分类Dev

Heredocs如何与xargs一起使用?

来自分类Dev

mongomock如何与电机一起使用?

来自分类Dev

CoGroupByKey如何与DistingingFiredPanes一起使用?

Related 相关文章

  1. 1

    如何定义与结构数组C一起使用的宏

  2. 2

    如何将valgrind与实际上是宏扩展的函数一起使用

  3. 3

    如何确定将_IONBF宏与setvbuf函数一起使用,文件操作速度很慢

  4. 4

    如何在Spring MVC中将宏与FreeMarker一起使用

  5. 5

    如何获取Scala命名和默认参数以与宏一起使用

  6. 6

    气流宏可以与CloudSqlInstanceExportOperator一起使用吗?

  7. 7

    将宏container_of与struct成员一起使用

  8. 8

    如何在计算机上创建可与任何Excel工作簿一起使用的Excel宏?

  9. 9

    如何将INDEX(MATCH())与重复值一起使用

  10. 10

    如何编写此正则表达式以与 preg_match 一起使用?

  11. 11

    如何使 INDEX 和 MATCH 与 VBA 中的文本一起使用?

  12. 12

    如何使PreferenceFragment与MainActivity一起使用

  13. 13

    如何与默认包装一起使用?

  14. 14

    backpatching如何与标记一起使用?

  15. 15

    getline如何与cin一起使用?

  16. 16

    如何使Powermock与Dexmaker一起使用

  17. 17

    如何使__debugInfo与XDebug一起使用?

  18. 18

    如何与gradle一起使用JMH?

  19. 19

    如何使TLS与Java一起使用?

  20. 20

    如何与JTextArea一起使用JScrollPane?

  21. 21

    如何与流星一起使用Prerenderio?

  22. 22

    如何与Eclipse一起使用TortoiseSVN

  23. 23

    如何与[if]一起使用[getElementById]?

  24. 24

    如何使Mixitup与Wordpress一起使用?

  25. 25

    如何使bbmustache与Elixir一起使用?

  26. 26

    RESTful如何与PHP一起使用?

  27. 27

    Heredocs如何与xargs一起使用?

  28. 28

    mongomock如何与电机一起使用?

  29. 29

    CoGroupByKey如何与DistingingFiredPanes一起使用?

热门标签

归档