我正在阅读“球拍王国”一书,第175页,我实际上看到了这段代码:
(struct dice-world (src board gt))
(struct game (board player moves))
(define (no-more-moves-in-world? w)
(define tree (dice-world-gt w))
(define board (dice-world-board w))
(define player (game-player tree))
player)
本书中的功能并不会返回播放器,但直到该行的所有内容都与书中一样。对我来说,这需要模式匹配的尖叫声!
事实上,这样做很好,对我来说更具可读性和显性:
(define (no-more-moves+? w)
(match w
[(dice-world _ board (game _ player _)) player]))
但是,我们仍然无缘无故地命名变量w
。我希望能够直接在函数参数上进行模式匹配,就像这样(语法无效):
(define (no-more-moves2? (dice-world _ board (game _ player _)))
player)
到目前为止,我的谷歌搜索似乎不可能?这听起来令人难以置信?我猜这可能是通过一些宏观诡计来实现的,但我真的很惊讶它不是从书中编写代码的标准方法吗?作为一本初学者的书,我想也许稍后会介绍模式匹配,但我根本没有在索引中找到它?
此外,如果答案是不可能/不习惯,我想知道它是否与其他lisps相同?
答案 0 :(得分:3)
是的,你绝对可以写这个宏。我认为这将是你的例子的长度,也许更短。
那么,为什么这不是这个惯用语呢?我认为基本的答案是:如果它不匹配会发生什么?如果您想提供多种模式怎么办?我猜你可能会来自Haskell背景,其中所有模式匹配定义都合并为一个函数。我认为Scheme对于打破整个函数定义仍然非常谨慎 被包裹在一对parens中,"更广泛地说,"范围是分隔的 用括号括起来。"这是真的,这在球拍中变得有点宽松 - 每一个 lambda现在可以立即在其中定义 - 但我认为一般 "味道"将使用你的第二种形式,在lambda中匹配 带有命名参数。
但是嘿 - 这是宏的用途:使用你觉得最可读的表格!我会的 如果你愿意的话,很乐意把这个宏放在一起。
答案 1 :(得分:3)
您可以从Racket match-plus package, under the name define/match*
获取所需的表单。免责声明:这是我的包裹。以下代码应该可以正常使用该模块:
(require match-plus)
(define/match* (no-more-moves2? (dice-world _ board (game _ player _)))
player)
要安装软件包,请使用DrRacket的软件包管理器GUI,或运行以下命令:
raco pkg install match-plus
我认为这个不被包含在Racket中的理由是John Clements提到的:使用这种形式,如果模式匹配失败,该函数只会引发异常。尽管如此,这对您的用例非常有用,特别是如果您在函数上签订合同。如文档所述:
...由于匹配模式与形式定义内联,因此只能指定一个匹配子句。这意味着如果模式匹配失败,则会引发错误,但如果函数已经以保证成功模式匹配的方式进行了约定,那么它是理想的。
(强调我的。)
答案 2 :(得分:3)
为了完整性,#lang racket
中还提供了define/match
,它比Alexis的解决方案稍微冗长一些,并且比身体中的match
略微冗长
#lang racket
(struct dice-world (src board gt))
(struct game (board player moves))
(define/match (no-more-moves-in-world? w)
[((dice-world _ _ (game _ p _))) p])