与 Racket 中的流进行模式匹配?

min*_*ief 4 stream pattern-matching racket

模式匹配是 let 子句中手动解构的一种非常易读的替代方法。我想知道是否可以将它与流一起使用,就像我们可以与列表一样。

作为说明,考虑一个简单的add-between实现来生成一个序列,其中在原始序列的每个元素之间插入一个元素。

(define (add-between lst sep)
  (match lst
    ['() '()]
    [(cons v vs)
     (cons v
           (cons sep
                 (add-between vs sep)))]))
Run Code Online (Sandbox Code Playgroud)

用法:

(add-between (list 'a 'b 'c) 'and) ; => '(a and b and c and)
Run Code Online (Sandbox Code Playgroud)

如果我们想对任意序列做同样的事情,比如流怎么办?

(define (add-between seq sep)
  (match seq
    ['() '()]
    [(cons v vs)
     (stream-cons v
                  (stream-cons sep
                               (add-between vs sep)))]))
Run Code Online (Sandbox Code Playgroud)

这会产生一个错误:

(add-between (stream 'a 'b 'c) 'and)
; match: no matching clause for #<stream>
; stdin:1:1
; Context:
;  /Applications/Racket v7.5/collects/racket/match/runtime.rkt:24:0 match:error
;  /Applications/Racket v7.5/collects/racket/repl.rkt:11:26
Run Code Online (Sandbox Code Playgroud)

如果我们可以对通用序列类型进行模式匹配,那将是理想的,因为这将封装列表和流。

Ale*_*uth 5

您可以为流定义自己的模式匹配形式,使用define-match-expander?带谓词和app带访问器。

#lang racket
(require syntax/parse/define (prefix-in * racket/stream))
(define (stream-empty? v) (and (stream? v) (*stream-empty? v)))
(define (stream-cons? v) (and (stream? v) (not (*stream-empty? v))))

(define-match-expander stream-cons
  (syntax-parser
    [(_ fst rst) #'(? stream-cons? (app stream-first fst) (app stream-rest rst))])
  (syntax-parser
    [(_ fst rst) #'(*stream-cons fst rst)]))

(define-match-expander stream*
  (syntax-parser
    [(_ rst) #'rst]
    [(_ fst more ... rst) #'(stream-cons fst (stream* more ... rst))])
  (syntax-parser
    [(_ init ... rst) #'(*stream* init ... rst)]))

(define-match-expander stream
  (syntax-parser
    [(_) #'(? stream-empty?)]
    [(_ elem ...) #'(stream* elem ... (? stream-empty?))])
  (syntax-parser
    [(_ elem ...) #'(*stream elem ...)]))
Run Code Online (Sandbox Code Playgroud)

使用它:

> (define (add-between seq sep)
    (match seq
      [(stream) (stream)]
      [(stream-cons v vs)
       (stream-cons v
                    (stream-cons sep
                                 (add-between vs sep)))]))
> (add-between (stream 'a 'b 'c) 'and)
#<stream>
> (stream->list (add-between (stream 'a 'b 'c) 'and))
'(a and b and c and)
Run Code Online (Sandbox Code Playgroud)

  • 我不确定任意序列。流工作得很好,因为它们像普通列表一样基于类似“cons”的结构,并且并非所有序列都可以方便地进行模式匹配 (3认同)