繁体   English   中英

斯卡拉在哈斯克尔的风格

[英]Scala's style val in Haskell

在Scala中,我可以表达一个函数,每次引用它时都会对它进行评估:

def function = 1 + 2 + 3

或仅评估一次的val

val val1 = 1 + 2 + 3

即使我多次打电话。

当然,在Haskell中,我可以定义一个函数(当我调用它时,它会反复评估):

function = 1 + 2 + 3

我可以在Haskell中定义Scala的val模拟吗?

更新:问题不在于懒惰的评估。

UPDATE2:

将评估function值的次数?

function = 1 + 2 + 3
main = do
        print function
        print function
        print function

Haskell没有指定很多方法来控制次数或命令事物的评估。也就是说,GHC最多只评估一次CAF (除非它们是类型多态)。 注意,对于(默认)单态限制, function = 1 + 2 + 3function定义为单态CAF,因此function最多被评估一次。

您还会发现许多人反对将此称为函数,因为除非您做了一些非常奇特的事情,否则它不是一个函数。 (其类型中没有箭头。)

你当然可以写:

let x = 1 + 2 + 3 in ...

代替

let myFunc () = 1 + 2 + 3 in ...

但是在Haskell中,考虑其中任何一个的评估频率并没有多大意义,除了如果计算需要它们两者至少评估一次,从不评估它们。

Haskell和Scala之间的关键区别在于,在Scala或任何其他严格语言中,绑定形式val x = 1 + 2 + 3告诉Scala评估表达式1 + 2 + 3并将其结果绑定到变量。 在Haskell,另一方面, let x = 1 + 2 + 3的绑定的计算1 + 2 + 3x和时,甚至是否计算表达式的问题是没有被决定let表达在所有。

由于Haskell绑定表单无法决定与其关联的表达式进行评估的策略,因此无法编写Scala版本的精确模拟。

编辑:忽略这个答案。 它只适用于没有优化的编译。 以我的斐波纳契实现为例, ghc -O0 -ddump-simpl main.hs在Core中给出了一个单独的fib定义:

Main.fib :: forall a_agB. GHC.Num.Num a_agB => () -> [a_agB]

但是使用O2优化进行编译ghc -O2 -ddump-simpl main.hs将斐波纳契列表实现为顶层的常量值

Main.$wfib :: forall a_agG. GHC.Num.Num a_agG => [a_agG]

然后由封闭的fibonacci实现调用它(它确实采用a ()参数)

Main.fib =
  \ (@ a_agG) (w_stM :: GHC.Num.Num a_agG) (w1_stN :: ()) ->
    case w1_stN of _ { () -> Main.$wfib @ a_agG w_stM }

结果是,当Main.fib没有得到记忆时, Main.$wfib仍然会被记忆并占用内存。


原答案如下:

正如丹尼尔瓦格纳在另一个答案中所说,这样的定义

val = 1+2+3

只会评估一次,除非它是多态的。 如果你想在每次引用它时进行评估,你就可以做到

val () = 1+2+3

这样你就必须将参数()赋予val ,但是它不会保存计算值。 如果val的计算值占用大量内存,但很容易计算,并且在需要时逐步消耗,这可能是一件好事。 例如,您可以拥有斐波那契数字列表:

fib = 0 : 1 : zipWith (+) fib (tail fib)

如果你现在做的话fib !! 100000 fib !! 100000 ,您需要计算所有前100,000个斐波纳契数。 fib表示此列表,因此它不能被垃圾收集,但会在内存中挂起。 为了解决这个问题,你可以做到

fib () = let x = 0 : 1 : zipWith (+) x (tail x) in x

由于fib现在是(常量)函数而不是常量值,因此不会保存其值,从而释放内存。

编辑:正如Philip JF在评论中所说,let表达式的内容可能被一个不友好的编译器解除,这将导致不必要的共享

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM