如何在Scheme中按正常顺序实现“if”?

问题描述 投票:0回答:1

我在学习 SICP 时读到了“应用顺序”和“正常顺序”。然后我尝试了练习 1-6 并研究了以下代码:

#lang racket
(define (p) (p))
(define (new-if test-expr then-expr else-expr)
  (cond (test-expr then-expr)
        (else else-expr)))

当我评估

(new-if (= 2 2) 5 (p))
时,它会进入死循环,因为
(= 2 2)
(p)
都被评估。所以我想知道如何按正常顺序制作这个
new-if
而不将
#lang racket
更改为
#lang lazy
,但我无法弄清楚。

> (new-if (= 2 2) 5 (p))
> 5
scheme lisp racket lazy-evaluation sicp
1个回答
0
投票

如果我们将

new-if
定义为函数:

(define (new-if test-expr then-expr else-expr) 
   ...)

然后在程序中

 (define (p) (p))
 (new-if (= 2 2) 5 (p))

形式

(new-if (= 2 2) 5 (p))
是一个函数调用。

函数调用(按正常顺序)按以下顺序进行评估:

  1. 评估
    new-if
    (评估我们的
    new-if
    程序)
  2. 评估
    (= 2 2)
    (评估为
    true
  3. 评估
    5
    (评估为
    5
  4. 评估
    (p)
    (导致循环)
  5. 现在使用参数调用
    new-if
    的结果(2.、3. 和 4. 的结果)。

问题当然是我们永远不会达到 5。

(p)
的求值会导致new-if 的主体被求值之前
无限循环。

这意味着,无论我们在

new-if

 的主体中放入什么,调用 
(new-if (= 2 2) 5 (p))
 总是会导致无限循环。

换句话说,在具有正常顺序语义的语言中,您无法将

new-if

 定义为正常函数。

(new-if e0 e1 e2)

的预期评估顺序是:

    评估
  1. e0
    ,我们将结果称为
    t
  2. 如果
  3. t
     非假,则评估 
    e1
    
    
  4. 否则
  5. t
    是假的,所以评估
    e2
    
    
  6. 结果是 2. 或 3. 的结果
此求值顺序与函数调用中的顺序不同。 因此

new-if

 必须定义为新形式。定义表单的机制
使用非标准评估顺序是
define-syntax
。它可以让你
将 
new-if
 定义为宏。

© www.soinside.com 2019 - 2024. All rights reserved.