在函数式语言中,函数是一等公民,因此调用它们不是我能做的唯一事情。我也可以把它们存起来。
现在,当我有一种默认情况下严格的语言时,我仍然没有被迫评估函数调用。我可以选择存储函数及其参数,例如在一个元组中供以后评估。
所以而不是
x = f a b c
我喜欢
x = (f,a,b,c)
之后,我可以用
之类的东西评估这件事eval (f,a,b,c) = f a b c
嗯,可能还有更多内容,因为我只想评估每个未评估的函数调用一次,但在我看来,这也可以通过数据结构来解决,这个数据结构比仅仅元组更有趣。
反过来也似乎是这种情况,因为例如在Haskell中,懒惰是默认的,我可以使用seq
或BangPatterns
强制执行评估。
所以说每个函数语言都有可能是懒惰的,这是正确的,但是大多数函数语言默认不是 ,因此需要额外的编程工作才能懒惰地调用函数,而默认情况下haskell 是懒惰的,需要额外的编程工作才能严格调用函数?
如果是这样的话,对于程序员来说更难的是:用严格的语言编写惰性函数调用或者用懒惰语言编写严格的函数调用?
作为旁注:Simon P. Jone严肃地说:" haskell的下一个版本将是严格的"。我首先想到这是一个笑话。但是现在我认为严格默认并不是那么糟糕,只要你可以在必要时变懒。
答案 0 :(得分:8)
低级别的懒惰评估是通过一个名为 thunk 的概念实现的,它包含两件事:
第一部分,闭包,可以用比函数及其参数的元组更简单的方式建模。您可以使用一个接受单位或无参数的函数(取决于您的语言的工作方式),并在其正文中将函数应用于参数。要计算结果,只需调用函数。
保罗约翰逊提到计划,这是一个完美的语言来证明这一点。作为Scheme宏(伪代码,未经测试):
(define-syntax delay
(syntax-rules ()
((delay expr ...)
;; `(delay expr)` evaluates to a lambda that closes over
;; two variables—one to store the result, one to record
;; whether the thunk has been forced.
(let ((value #f)
(done? #f))
(lambda ()
(unless done?
(set! value (begin expr ...))
(set! done? #t))
value)))))
(define (force thunk)
;; Thunks are procedures, so to force them you just invoke them.
(thunk))
但是要回到问题的标题:这是否意味着每种功能语言都可能是懒惰的?答案是否。渴望的语言可以实现thunking并使用它在用户选择的位置提供选择性延迟评估 ,但这与像Haskell实现提供的普遍延迟评估相同。
答案 1 :(得分:1)
你建议的是什么。在Scheme中执行此操作的详细信息可以是found in SICP。人们可以设想一个严格的Haskell版本,其中有一个" lazy"与" seq"相反的功能。在哈斯克尔。然而,将其添加到类似Haskell的严格语言中需要编译器魔法,否则thunk会在传递给" lazy"之前被强制使用。
然而,如果你的语言具有不受控制的效果,那么这可能会变得毛茸茸,因为每当它的封闭函数被评估时就会发生效果,并且弄清楚什么时候在懒惰的语言中发生这种情况很困难。这就是为什么Haskell有IO monad。