【问题标题】:Why is there no (dict (k v)...) pattern in (match)?为什么 (match) 中没有 (dict (k v)...) 模式?
【发布时间】:2018-01-14 11:34:44
【问题描述】:
这里是初学者问题,我只花了几个小时学习该语言。
Racket 具有 dictionaries,由哈希表、对列表等实现。(match) 函数可识别 (hash-table (pat pat)...)、(list-no-order pat...) 等,但不能识别 (dict (pat pat)...)。
我认为在dict 接口上进行模式匹配会很有用,原因与拥有该接口的用处相同。它的遗漏表明情况并非如此。谁能告诉我我错过了什么?如果我想在可能是散列或对列表的数据上使用(match),我应该有两个子句吗?完全不同的东西?
【问题讨论】:
标签:
pattern-matching
racket
【解决方案1】:
我的最佳猜测:没有人觉得有必要为match 实现dict 模式。幸运的是 match 是可扩展的。 define-match-expander 形式可用于扩展match 可以处理的模式集。
假设我们想要
(dict (k0 v0) (k1 v1))
意思是一样的
(or (hash-table (k0 v0) (k1 v1)
(list-no-order (cons k0 v0) (cons k1 v1))
(对于具有两个以上键值对的模式也类似)
然后我们可以像这样定义一个匹配扩展器:
(define-match-expander dict
(λ (stx)
(syntax-case stx ()
[(_dict (key-pat val-pat) ...)
#'(or (hash-table (key-pat val-pat) ...)
(list-no-order (cons key-pat val-pat) ...))])))
现在match 可以理解(dict ("a" a) ("b" b) ("c" c)) 这样的模式。
一个完整的例子:
#lang racket
(define-match-expander dict
(λ (stx)
(syntax-case stx ()
[(_dict (key-pat val-pat) ...)
#'(or (hash-table (key-pat val-pat) ...)
(list-no-order (cons key-pat val-pat) ...))])))
(define (keys+vals a-dict)
(match a-dict
[(dict ("a" a) ("b" b))
(list a b)]))
(keys+vals (hash "a" 1 "b" 2)) ; gives '(1 2)
(keys+vals '(("b" . 5) ("a" . 4))) ; gives '(4 5)