【问题标题】:Which stage make difference between call-by-name and call-by-value?哪个阶段在按名称调用和按值调用之间有所不同?
【发布时间】:2016-02-20 03:33:08
【问题描述】:

大多数其他语言都使用按值调用。 Haskell 使用按名称调用(惰性评估),我想知道它是如何运行的,我认为与按值调用相比会更好。

以问题为例,
repeat' 函数定义如下:

repeat' :: a -> [a]   
repeat' x = x:repeat' x

使用repeat' 3会得到一个无限的3个列表,
ghci> repeat' 3会产生3个连续的,
take 5 (repeat' 3) 只会得到[3,3,3,3,3]
haskell 如何知道以第五次递归内部 repeat' 函数结束?此外,我认为这不是take 的问题。

代码在哪个阶段执行与按值调用不同?

谢谢

【问题讨论】:

  • 总之,总是减少最外层的表达式,它是可约的:head (repeat 3) -> head (3:repeat 3) -> 3。在第一种情况下,head 是不可约的,因为它必须对其参数进行模式匹配,但它的参数不是构造函数。但是,repeat 没有模式匹配,所以总是可以减少它。第一次归约后,head 现在可以归约,因为有一个构造函数(:)。
  • "当代码被执行到哪个阶段它与按值调用不同?" erm...什么?您是否在问类似这样的问题:假设我们使用按值调用作为传递函数参数的策略而不是按名称调用,这会有所不同吗?我相信对于按名称调用-值你实际上是指急切减少,在这种情况下repeat 3 只是undefinedtake 5 undefined = undefined 并且程序将永远卡住。
  • @Bakuriu,您可以将按名称调用视为惰性求值(理解起来会更好)。只要编译器可以,表达式可以进行求值时,将使用按值调用,当然,Haskell 不使用按值调用。我不明白你说 repeat 3 is just undefined 以及它将被评估的点。大多数其他语言(如 c/c++)使用按值调用,我想知道如何Haskell 是否处理 undefined(重复 3)?谢谢

标签: haskell lazy-evaluation


【解决方案1】:

您将获得无限的 3 列表,因为在交互式会话中键入 repeat' 3 本质上会调用 show (repeat' 3),而 show 会尝试遍历 repeat' 3 的整个返回值。另一方面,take 仅尝试从列表中获取有限数量的元素。这是前奏曲中的定义:

take n _      | n <= 0 =  []
take _ []              =  []
take n (x:xs)          =  x : take (n-1) xs

repeat'repeat' x = x:repeat' x的定义与take匹配的模式进行比较。当您调用take 5 (repeat' 3) 时,将应用最后一个模式,因此它变为take 5 (3:repeat' 3) = 3 : take 4 (repeat' 3)。由于惰性评估,repeat' 仅在任何给定步骤进行必要的评估,在这种情况下,这意味着提取第一个元素以匹配模式x:xs。因此,take 建立了一个由 5 个 3 组成的列表,当 take 0 (repeat' 3) 匹配并且递归终止时终止,忽略对 repeat' 的未评估调用以返回一个空列表。

【讨论】:

  • 你的意思是说take开头把3s当成空列表吗?但是当take尝试访问repeat 3时,表达式不会是评估?
  • 它从不将(repeat' 3) 视为一个空列表;相反,它在任何时候都不会看到除了头部之外的任何东西。未计算的尾部被传递给递归调用。
  • 此外,未评估的尾部在哪一点被评估为内部take
猜你喜欢
  • 2015-06-07
  • 2013-10-02
  • 2017-02-07
  • 2015-05-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-15
  • 2017-01-17
  • 2019-10-19
相关资源
最近更新 更多