如何使用模式匹配宏

By guenchi at 2018-09-07 • 1人收藏 • 229人看过

作者:guenchi 

 

Dan FriedmanErik Hilsdale 和 Kent Dybvig 写了一个屌炸天的宏,为Scheme实现了模式匹配。


我将它封装成了r6rs库,你可以在这个地址获取它:


https://github.com/guenchi/match


或者直接 raven install match


导入它到你的代码:

(import (match match))


match接受一个list,用来和你设定的模式对比:

(match '(a 1 2)
    ((a ,x ,y) x))

比如这个,它的意思是固定了car必须是'a。

你也可以设定固定的数字或者符号。

,x ,y 代表它可以是任意的东西。后一个x 用来返回位于这个地方的值。

你也可以在模式匹配里使用点操作符:

(match '(a 1 2 3)
    ((a ,x ...) `(,x ...)))

如上所示,你可以接受任意个元素,只要它的一开始是'a。

同样用点操作符来将这些元素合并成list。

也许你会想限定一些元素的类型,或者做一些其他判断...

你可以这样写:

(match '(a 1 2)
    ((a ,x ,y) (guard (symbol? x)) y))

(guard)过程接受一个布尔值,当它接受false时,便对此匹配项行使一票否决权!

其他部分匹配的再完美也没用。

这个模式匹配宏的牛逼之处在于它可以进行无限嵌套:

我们先来定义一个匹配:

(define Expl
    (lambda (x)
        (match x
            ((a ,x) x))))

然后你就可以用 ,(Expl -> e) 调用它:

比如

(match '(a (a 3) 2)
    ((a ,(Expl -> e) ,y)  e))

匹配项的第二个元素是我们的 ,(Expl -> e) ,这个时候,第二项就会被送入Expl这个过程进行匹配。只有当它满足匹配,match才会继续匹配外层。

这个例子会返回3.

注意的是  ,(Expl -> e) 的e 没有"," 。


有了这些解释,现在你应该不难看懂下面这个模式匹配过程了:

;;; <Prog> -> (program <Stmt>* <Expr>)
;;; <Stmt> -> (if <Expr> <Stmt> <Stmt>)
;;;         | (set! <var> <Expr>)
;;; <Expr> -> <var>
;;;         | <integer>
;;;         | (if <Expr> <Expr> <Expr>)
;;;         | (<Expr> <Expr*>)

(define parse
    (lambda (x)
        (define Prog
            (lambda (x)
                (match x
                    [(program ,[Stmt -> s*] ... ,[Expr -> e])
                        `(begin ,s* ... ,e)]
                    [,other (error 'parse "invalid program ~s" other)])))
        (define Stmt
            (lambda (x)
                (match x
                    [(if ,[Expr -> e] ,[Stmt -> s1] ,[Stmt -> s2])
                        `(if ,e ,s1 ,s2)]
                    [(set! ,v ,[Expr -> e])
                        (guard (symbol? v))
                            `(set! ,v ,e)]
                    [,other (error 'parse "invalid statement ~s" other)])))
        (define Expr
            (lambda (x)
                (match x
                    [,v (guard (symbol? v)) v]
                    [,n (guard (integer? n)) n]
                    [(if ,[e1] ,[e2] ,[e3])
                        `(if ,e1 ,e2 ,e3)]
                    [(,[rator] ,[rand*] ...) 
                        `(,rator ,rand* ...)]
                    [,other (error 'parse "invalid expression ~s" other)])))
        (Prog x)))
        
(parse '(program (set! x 3) (+ x 4))))
     => (begin (set! x 3) (+ x 4))


1 个回复 | 最后更新于 2018-09-07
2018-09-07   #1

666

登录后方可回帖

登 录
信息栏

Scheme中文社区

推荐实现 ChezScheme / r6rs / r7rs large
theschemer.org
Q群: 724577239

精华导览

社区项目

包管理器:Raven
HTTP服务器:Igropyr (希腊火)
官方插件:vscode-chez

社区目标:

完善足以使Scheme工程化和商业化的库,特别是开发极致速度的Web服务器和ANN模块。

一直以来Scheme缺少一个活跃的中文社区,同时中文资料的稀少,导致大多数因为黑客与画家和SICP而接触Scheme的朋友,在学完SICP后无事可做,不能将Scheme转换为实际的生产力。最后渐渐的放弃。
同时Chicken等实现,却因效率问题无法与其他语言竞争。本社区只有一个目的,传播Scheme的文明之火,在最快的编译器实现上,集众人之力发展出足够与其他语言竞争的社区和库。


友情链接:

Clojure 中文论坛
函数式·China


Loading...