This match
binds identifiers a
and b
to the prefix '(0 1)
and the suffix '(3 4 5)
of the list:
(match '(0 1 2 3 4 5)
[`(,a ... 2 ,b ...)
(values a b)])
Another equivalent version:
(match '(0 1 2 3 4 5)
[`(,@(list a ... 2) ,b ...)
(values a b)])
How to bind an identifier (within the pattern itself) to the prefix '(0 1 2)
, including the delimiter?
The app
pattern, which invokes a function with the value being matched and then matches the values it returns, combined with a version of splitf-at
that includes the partition element in the first list instead of the second, can be used to do this:
; 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)))
(Note the use of (? list? ...)
to make sure the value is a list before trying to call any functions that depend on that.)
You can define a match extender to make it nicer-looking:
(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)))
This version also includes a check to make sure the value you want to split on is actually in the list, or it'll fail to match.