球拍:模式匹配功能参数

时间:2016-03-25 21:48:32

标签: pattern-matching racket

我正在阅读“球拍王国”一书,第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相同?

3 个答案:

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