美文网首页程序员
Scheme宏的二三事

Scheme宏的二三事

作者: elon_wen | 来源:发表于2019-11-09 16:00 被阅读0次

一次造轮子的经历

因为我的Scheme入门书是Dan Friedman的《The Little Schemer》,老爷子从头到尾都没有提到过if。所以一直到翻完整本书,对于只有2个分支的逻辑,我也是用这么“蠢萌”的方式写的(这里的cond可以理解成if的多分支的版本):

(define (my-abs x)
  (cond ((>= x 0) x)
            (else (- x))))

所谓杀鸡焉用牛刀,既然“if-then-else”的简洁性摆在那里,造轮子的事肯定也是干过的:

(define (my-if predicate then-clause else-clause)
  (cond (predicate then-clause)
            (else else-clause)))

通过自定义my-if函数,我们自己实现了if的功能。来测试一下:

(my-if (= 1 2) 0 1)
;Value: 1

(my-if (= 1 1) 0 1)
;Value: 0

scheme的波兰表达式写法,让自定义函数和默认关键字之间没有明显的区分。接下来就可以把最开始的my-abs改写的简短一点:

(define (my-abs x)
  (my-if (>= x 0) x (- x)))

在很长一段时间里这个my-if都可以很好的运行,直到有一天...

应用序和正则序

事情是这样的:之前替换的都是比较简单的场景,而这一次在cond中存在一个递归的函数调用,当再次运行的时候,发现程序无法退出了。下面是这个例子的简化版本,原始版本参考SICP[1]的32页。

; 某个递归调用自己的函数
(define (bomb) (bomb))

; 某个可以正常执行的代码片段
(cond ((= 1 1) 1)
      (else (bomb)))

; 陷入无限递归
(my-if (= 1 1) 1 (bomb))

让我们在仔细审视一下cond的求值过程:解释器会按顺序判断谓词逻辑是否成立,一旦(= 1 1)返回的结果为true,那么立刻返回1,并且 忽略 后续所有的谓词和对应的表达式,也就是说(bomb)根本没机会执行。

my-if其实是一个函数调用,遵循2种可能的求值方式:应用序(applicative-order)或者正则序(normal-order)。

先看一个直观一点的例子[2]

(define (double x)
    (+ x x))

(double (+ 2 1))

对于应用序,会首先求出(+ 2 1)的值,然后带入double的定义中,也就是说+一共执行了 2 次,1次是计算(+ 2 1),1次是计算(+ 3 3)

对于正则序,则会先展开double的定义,整个表达式变成(+ (+ 2 1) (+ 2 1)),然后对于(+ 2 1)分别求值 2 次,最后再相加,整个过程中+一共执行了 3 次。

再回过头看之前所遇到的问题,如果采用正则序,在遇到my-if时会先将其展开,然后再将参数带入,也就是和之前直接用cond写的没有区别。而应用序则相反,会先对于参数求值,然后再执行函数调用。也就是说,无论my-if是用什么方式定义的,(= 1 1)1(bomb)都会被先求值,而当(bomb)被求值时程序就陷入无限递归了。

我知道的几乎所有的编程语言(包括流行的Java、Python,也包括不太流行的Scheme)都选择了应用序作为求值方式。这也导致了我之前甚至连什么是正则序都不知道(至于正则序、惰性求值之类易混淆的概念,后面有机会再写一篇)。

再造一次轮子

在这次失败的经历后的某天,结合另一个我之前一直想不明白的问题:宏到底有什么作用?我突然就经历了一个“尤里卡时刻”:为什么不试试用宏来重新定义my-if

(define-syntax my-if
  (syntax-rules ()
    ((my-if predicate then-clause else-clause)
    (cond (predicate then-clause)
          (else else-clause)))))

通过define-syntax我们定义了一个宏,语法的部分我不做赘述。可以看到,通过把my-if展开为cond对应的表达式,我们实现了需要的功能,因为宏展开是基于正则序的

顺带一提的是,我们通过宏,几句话就实现了自定义语法,这也正是Lisp系语言元编程的能力。

相关文章

  • Scheme宏的二三事

    一次造轮子的经历 因为我的Scheme入门书是Dan Friedman的《The Little Schemer》,...

  • 孙宏泉先生的二三事

    简 书 刘春琪 赵咸熙 (执笔) 在我们从事三十多年医疗卫生工作中,孙宏泉先生是最熟悉的...

  • 看图写诗

    二零二三一祝福, 零感如泉才思涌。 二零二三二祝福, 三阳开泰展宏兔。

  • 《晋书阮籍传》 阮籍先生二三事

    ❤阮籍先生❤二三事 摘自《晋书 阮籍传》 笔记: 先生志气宏放而不羁,隽才绝异,惊才艳艳…… 穆然想起余光中先生的...

  • ChezScheme 9.5.3 MinGW 编译

    Chez Scheme 的传说 王垠 - Chez Scheme 的传说 Chez Scheme Project ...

  • URL Scheme

    URL Scheme是什么URL Scheme有什么作用URL Scheme怎么使用 URL Scheme是什么 ...

  • 《暖心二三事》目录

    【记录生活中的点滴暖心事】 第一篇:暖心二三事① 第二篇:暖心二三事② 第三篇:暖心二三事③ 第四篇:暖心二三事④...

  • data:image/png;base64用法

    参考文章:前端-Data URI Scheme Data URI Scheme data URI scheme 允...

  • Web跳转App

    scheme://host?param0=123NSString *scheme =url.scheme;NSSt...

  • 近期工作总结(2016.7-2016.9)

    URL Scheme App间跳转,Safari跳App:配置URL Scheme的scheme为自定的特殊字段,...

网友评论

    本文标题:Scheme宏的二三事

    本文链接:https://www.haomeiwen.com/subject/uhgoyctx.html