Chez Scheme过程参数的求值顺序

By qzivli at 16 天前 • 0人收藏 • 90人看过

Scheme有意不对过程参数的求值顺序加以规定,每个Scheme实现的参数求值顺序都可能是不同的,可能是从左到右(像Common Lisp那样),也可能是从右到左,还可能是其他任意顺序。


Chez Scheme的参数求值顺序比较奇特,看起来就像是参数被两两分组入栈,然后再出栈。例如:

(f a   b  c  d  e)
   ╰──╯ ╰──╯

a, b一组入栈,c, d一组入栈,e落单了,单独入栈;然后再出栈。求值顺序是e, c, d, a, b。

4 个回复 | 最后更新于 15 天前
15 天前   #1

出入栈是调用约定的说法,和求值顺序没有关系。

Chez的求值顺序比较复杂,常见的情况有以下几种:

1、在REPL中输入简单的表达式(复杂的会走编译器),此时走的是cheat-eval

> (list (display 1) (display 2) (display 3) (display 4) (display 5))
53412(#<void> #<void> #<void> #<void> #<void>)

副作用的顺序是53412,和楼主的一致,这个顺序实际上来源于map

2、走编译器,primitive被inline

> (define f (lambda () (list (display 1) (display 2) (display 3) (display 4) (di
splay 5))))
> (f)
12345(#<void> #<void> #<void> #<void> #<void>)

这个时候副作用顺序取决于具体的primitive。例如上面的list(或者换成vector)就是12345,这个顺序来源于list-bind。

3、走编译器,没有inline的调用

> (define f (lambda (k) (k (display 1) (display 2) (display 3) (display 4) (disp
lay 5))))
> (f list)
54321(#<void> #<void> #<void> #<void> #<void>)

副作用从右至左,然后取值,这个是正常的顺序,来源于np-remove-complex-opera*的Triv*。


以上是几种常见的副作用顺序,但是求值顺序不只是副作用顺序,

> (define a 1)
> (list a (set! a 2) a (set! a 3) a)
(3 #<void> 1 #<void> 1)
> a
2
> (define (f k)
    (let ([a 1])
      (k a (set! a 2) a (set! a 3) a)))
> (f list)
(2 #<void> 2 #<void> 2)
> (define (f)
    (let ([a 1])
      (list a (set! a 2) a (set! a 3) a)))
> (f)
(1 #<void> 2 #<void> 3)

这表明1和2中,取值是紧接在对应的副作用之后的;而3则是位于所有副作用之后。


以上反映了Chez求值顺序的不确定性,任何的优化都可能将其改变,因此我们不能写依赖求值顺序的代码。

15 天前   #2

回复#1 @qww6 :


感谢老师的解释 :-)

15 天前   #3

回复#1 @qww6 :

学习了

15 天前   #4

总结:


带 ! 的是魔鬼!

登录后方可回帖

登 录
信息栏

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...