2013-04-16 39 views
4

可以找到问题here寻求对SICP练习的一些解释1.5

在这本书中,我发现正常秩序评价的一个描述是:

“,直到需要有自己的价值观相反,它会首先,直到它得到另一种评价模型不会评估操作数为参数替代操作数表达式一个只涉及原始操作符的表达式,然后执行评估。“

我还发现了另一个描述:“完全展开,然后缩小”。

在练习中,我认为p的定义类似于(lambda() (p)), ,它永远不会展开为原始操作符,因此永远不会终止。

然而,另一方面,谷歌搜索这个问题的一些答案后,似乎正常的顺序评估应该终止,因为它只根据需要评估的东西,实际上(p)将不会被评估。

所以我认为“展开”和“评估”之间一定有区别,而解释者在这里做的是评估事物。

究竟是什么区别,或者 是否有一些我已经遗漏的点?

另一个问题:我应该说“(p)评估为(p)”或“(p)扩展为(p)”吗?

回答

6

如果要求评估(p),那么应用订单评估人员不会终止。然而,这个问题提到if有一个特定的评估语义,它由应用程序和正常顺序的评估人员共享。具体而言,“假设解释器使用正常顺序或适用顺序,特殊形式if的评估规则相同:首先评估谓词表达式,然后结果确定是评估后果还是替代表达式。”

从锻炼的代码是

(define (p) (p)) 

(define (test x y) 
    (if (= x 0) 
    0 
    y)) 

和所考虑的测试是

(test 0 (p)) 

正常顺序的评价是“完全展开,然后降低”选项。下正常顺序评估,(test 0 (p))完全膨胀为

(test 0 (p)) == 
(if (= 0 0) 
    0 
    (p)) 

由于if具有上述的语义,并且在膨胀测试条件为(= 0 0),这是真实的,所述正常顺序评估确定评估结果,这是0,所以表达式的值是0

然而使用应用性阶评价,在评价(test 0 (p))的第一步是评估表达式test0,和(p),然后调用“应用”,因此“应用性”的值test与评估0(p)产生的值。由于(p)的评估不会完成,因此(test 0 (p))的评估也不会。

+1

这就是我错过的观点!预测'(= 0 0)'决定仅评估后续部分,忽略'(p)'的扩展。 – Javran

3

根据正常评估规则,(p)将通过调用函数p而不带任何参数进行评估。例如(在Common Lisp中):

> (defun p() 
    5) 
    => P 
> (p) 
    => 5 

你的问题开始时提到了一种被称为“懒惰评估”的事情。 Common Lisp默认不会这样做;它从左向右评估函数的所有参数。计划没有规定他们的评估顺序,只是他们会这样做。

但是,在评估事物之前,需要对它们进行扩展(这可能意味着lisp中的许多事情),从而使lisp能够控制评估顺序。例如,p可能是一个宏。在这种情况下,正常的评估规则不一定适用。再次,在Common Lisp中:

> (defmacro p() 
    (print "I'm being expanded!") ; print on expansion 
    (terpri) ; new line. 
    `(progn (print "I'm being evaluated!") ; print on evaluation 
      (terpri) 
      5)) 
    => P 

这是进入读取评估打印循环。表达式被读取,然后展开,评估,然后打印。

> (p) 
    I'm being expanded! 
    I'm being evaluated! 
    => 5 

要停止正在评估的扩展,让我们把它放在一个lambda中。您会注意到它仍然会打印扩展消息。

> (defvar foo (lambda() (p))) 
    I'm being expanded! 
    => COMPILED FUNCTION #<LAMBDA> 

现在我们称之为,并对表格进行评估。

> (funcall foo) ; call the function 
    I'm being evaluated! 
    => 5 

您可以自行展开宏调用。

> (macroexpand-1 '(lambda() (p))) 
    I'm being expanded! 
    => (lambda() (progn (print "I'm being evaluated!") 
         (terpri) 
         5)) 

Haskell等语言在默认情况下有懒评估。在你引用的段落中,SICP让你想象一个懒惰的lisp版本。对于这样一个lisp的工作,只评估需要的东西,它不仅需要盲目扩展和评估所有东西,直到它达到一个价值(参见关于SICP替代模型的讨论),而是扩展事物和只有在具体询问他们的价值时才对其进行评估。您可以将此与上面的示例进行比较,我们在其中扩展了lambda表达式主体中的宏P,并在需要该值时强制使用FUNCALL进行评估。稍后在SICP中,您将使用类似的技术来实现惰性列表。正如我所说的,Haskell自动完成这样的事情,不难想象一个lisp也会这样做(尽管目前还没有流行的)。考虑到本书中的实际问题,我想我会进一步讨论一下,但希望你对如何评估什么是评估什么,什么时候什么,以及它可以产生什么差异有了一些想法。

+0

您的回答很有帮助,我无法同时接受两个答案,这让我感到很尴尬。 1.我可以说“扩展”是评估一个宏的过程,然后把结果放在宏调用的地方,而当我们强制执行一些计算时,“评估”就完成了。 2.很好的比喻,正常顺序与应用顺序是类似于哈斯克尔的懒惰与严谨:) – Javran