什么是“按名称调用”?

21

我在做一项作业任务,要求我们在我们所开发的语言中(使用Scheme),实现一种称为“按名传递”的评估策略。

我们被提供了一个Scala示例,但我不理解“按名传递”是如何工作的,以及它与“按需传递”有何不同?

3个回答

31

按需调用是呼叫方式的记忆化版本(call-by-name),具体请参见维基百科

在按名字调用中,参数每次使用时都会被评估(evaluate),而在按需调用中,参数第一次使用时被评估,并记录下其值,这样随后就不需要重新评估。


我已经实现了按需调用,当我第一次实现的时候没有缓存,我觉得教授要求我做一些我已经完成的事情毫无意义。因此,我想要了解按需调用和按名字调用之间的真正区别。 - forellana
我已经确认过了教授的意思,那是所谓的按名称调用,我很困惑因为我们已经写过那段代码,现在他又要我们再写一遍。 - forellana

19

按名称调用是一种参数传递方案,其中参数在使用时进行评估,而不是在函数被调用时。以下是一个伪C语言的示例:

int i;
char array[3] = { 0, 1, 2 };

i = 0;
f(a[i]);

int f(int j)
{
    int k = j;    // k = 0
    i = 2;        // modify global i
    k = j;        // The argument expression (a[i]) is re-evaluated, giving 2.
}

当使用当前参数表达式的值访问时,该参数表达式是惰性地计算。


1
惰性求值是最多评估一次,按需调用是零次、一次或多次评估。 - Randall Schulz
我不了解Scheme,但在Scala中(它没有惰性参数),这种区别是完全准确的。 - Randall Schulz
这个函数最后应该打印(k)吗?返回值是什么? - tonythestark

3

在上面的答案中添加以下内容:

阅读SICP流部分。它很好地解释了按名称调用和按需调用,并展示了如何在Scheme中实现它们。顺便说一句,如果你正在寻找一个快速的解决方案,这里有一个基本的按需调用在Scheme中实现:

 ;; Returns a promise to execute a computation. (implements call-by-name)
 ;; Caches the result (memoization) of the computation on its first evaluation
 ;; and returns that value on subsequent calls. (implements call-by-need)
 (define-syntax delay
    (syntax-rules ()
      ((_ (expr ...))
       (let ((proc (lambda () (expr ...)))
             (already-evaluated #f)
             (result null))
         (lambda ()
           (if (not already-evaluated)
               (begin
                 (display "computing ...") (newline)
                 (set! result (proc))
                 (set! already-evaluated #t)))
           result)))))

 ;; Forces the evaluation of a delayed computation created by 'delay'.
 (define (my-force proc) (proc))

一个样例运行:

> (define lazy (delay (+ 3 4)))
> (force lazy) 
computing ... ;; Computes 3 + 4 and memoizes the result.
7
> (my-force lazy) 
7 ;; Returns the memoized value.

“delay”和“force”是r5rs的标准,但实际上它们至少与r3rs一样古老。 - Nietzche-jou
@sgm 是的,它们是标准的一部分。我只是想展示如何实现它们。 - Vijay Mathew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接