以下两个公式有什么区别?
cp [] = [[]]
cp (xs:xss) = [x:ys | x <- xs, ys <- cp xss]
----------------------------------------------
cp [] = [[]]
cp (xs:xss) = [x:ys | x <- xs, ys <- yss]
where yss = cp xss
样本输出: cp [[1,2,3],[4,5]] => [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]]
根据Haskell的功能思维(p。92),第二个版本是“更有效的定义... [它保证cp xss仅被计算一次”,尽管作者从未解释过为什么。我会以为它们是等效的。
当然,这两个定义在表示相同值的意义上是等效的。
在操作上,它们在按需呼叫评估下的共享行为不同。jcast已经解释了原因,但是我想添加一个快捷方式,该方式不需要明确地取消列表的理解。规则是:语法上依赖于变量的任何表达式x
都会在每次变量x
绑定到值时重新计算,即使该表达式实际上并不依赖于x
。
在你的情况下,在第一个定义,x
是在范围在位置cp xss
出现,所以cp xss
将重新评估每个元素x
的xs
。在第二个定义中cp xss
出现在的范围之外,x
因此将只计算一次。
然后适用通常的免责声明,即:
不需要编译器遵守按需调用评估的操作语义,仅遵循指称语义。因此,它可能比根据上述规则期望的次数少(上浮)或次数多(上浮)。
总的来说,分享更多更好是不正确的。例如,在这种情况下,它可能不会更好,因为cp xss
增长的大小与最初计算它所花费的工作量一样快。在这种情况下,从内存中读取值的开销可能会超过重新计算该值的开销(由于缓存层次结构和GC)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句