提问人:formalizm 提问时间:2/21/2023 更新时间:2/22/2023 访问量:73
如何将标识符绑定到子列表加分隔符?
How to bind an identifier to a sublist plus delimiter?
问:
这会将标识符绑定到列表的前缀和后缀:match
a
b
'(0 1)
'(3 4 5)
(match '(0 1 2 3 4 5)
[`(,a ... 2 ,b ...)
(values a b)])
另一个等效版本:
(match '(0 1 2 3 4 5)
[`(,@(list a ... 2) ,b ...)
(values a b)])
如何将标识符(在模式本身内)绑定到前缀,包括分隔符?'(0 1 2)
答:
1赞
Shawn
2/22/2023
#1
该模式调用一个具有匹配值的函数,然后匹配它返回的值,并结合在第一个列表而不是第二个列表中包含分区元素的 splitf-at
版本,可用于执行此操作:app
; Like splitf-at but includes the element to split at in the first value not the second
(define (splitf-at/inclusive lst pred?)
(let loop ([lst lst]
[first-res '()])
(cond
((empty? lst)
(values (reverse first-res) '()))
((pred? (car lst))
(loop (cdr lst) (cons (car lst) first-res)))
(else
(values (reverse (cons (car lst) first-res)) (cdr lst))))))
; Gives '(0 1 2) '(3 4 5)
(match '(0 1 2 3 4 5)
((? list? (app (lambda (lst) (splitf-at/inclusive lst (negate (curry = 2)))) a b))
(values a b)))
(请注意,在尝试调用依赖于该值的任何函数之前,请使用 来确保该值是一个列表。(? list? ...)
您可以定义匹配扩展器以使其看起来更漂亮:
(define-match-expander split-list
(lambda (stx)
(syntax-case stx (...)
((split-list x (... ...) val y (... ...))
#'(? (lambda (lst) (and (list? lst) (member val lst)))
(app (lambda (lst) (splitf-at/inclusive lst (lambda (elem) (not (equal? elem val))))) x y))))))
; Also gives '(0 1 2) '(3 4 5)
(match '(0 1 2 3 4 5)
((split-list a ... 2 b ...)
(values a b)))
此版本还包括一项检查,以确保要拆分的值实际上在列表中,否则将无法匹配。
评论
0赞
formalizm
2/25/2023
谢谢@Shawn,这是一个很好的方法,我会使用它。
0赞
formalizm
2/25/2023
不过,对缺点的一些评论:1)第一个“......”在这个匹配扩展器中并不贪婪,不像通常的 match 省略号(这当然很容易修复),2) 与匹配中的列表模式相比,这种语法非常严格。例如,最好允许任意数量的标识符和嵌套列表子模式,并在其中捕获一些标识符。这超出了我的问题范围,但需要跟进(使用匹配扩展器转换为列表子句),我会考虑一下。
下一个:如何避免匹配枚举时出现语法重复?
评论