Dav*_*vid 246 syntax haskell lazy-evaluation
当我尝试使用真实项目来驱动Haskell时,我遇到了以下定义.我不明白每个论点前面的感叹号是什么意思,我的书似乎没有提到它.
data MidiMessage = MidiMessage !Int !MidiMessage
Run Code Online (Sandbox Code Playgroud)
Cur*_*son 295
这是严格的声明.基本上,这意味着在创建数据结构值时必须将其评估为所谓的"弱正常头部形式".让我们看一个例子,这样我们就可以看到这意味着什么:
data Foo = Foo Int Int !Int !(Maybe Int)
f = Foo (2+2) (3+3) (4+4) (Just (5+5))
Run Code Online (Sandbox Code Playgroud)
f在评估时,上面的函数将返回一个"thunk":即执行以找出其值的代码.那时,Foo甚至还不存在,只是代码.
但在某些时候,有人可能会尝试查看它,可能是通过模式匹配:
case f of
Foo 0 _ _ _ -> "first arg is zero"
_ -> "first arge is something else"
Run Code Online (Sandbox Code Playgroud)
这将执行足够的代码来完成它所需要的,而不是更多.所以它会创建一个带有四个参数的Foo(因为如果没有它,你就无法查看它).首先,因为我们正在测试它,我们需要一直评估4,我们发现它不匹配.
第二个不需要评估,因为我们没有测试它.因此,6我们只是存储代码以供以后评估,而不是存储在该内存位置(3+3).只有当有人看着它时,它才会变成6.
但是,第三个参数!位于其前面,因此严格评估:(4+4)执行,并8存储在该内存位置.
第四个参数也是严格评估的.但是这里有点棘手:我们的评估并不完全,只是对于正常的头部形态.这意味着我们弄清楚它是否Nothing或Just什么的,和商店,但我们就不再继续.这意味着我们不会存储,Just 10但实际上Just (5+5),将thunk保留在未评估状态.重要的是要知道,尽管我认为这样做的所有含义都超出了这个问题的范围.
如果启用BangPatterns语言扩展,则可以以相同的方式注释函数参数:
f x !y = x*y
Run Code Online (Sandbox Code Playgroud)
f (1+1) (2+2)将返回thunk (1+1)*4.
Chr*_*way 83
查看strict和非严格构造函数参数之间区别的一种简单方法是它们在未定义时的行为方式.特定
data Foo = Foo Int !Int
first (Foo x _) = x
second (Foo _ y) = y
Run Code Online (Sandbox Code Playgroud)
由于非严格参数未被评估second,因此传入undefined不会导致问题:
> second (Foo undefined 1)
1
Run Code Online (Sandbox Code Playgroud)
但严格的论证不可能undefined,即使我们不使用该值:
> first (Foo 1 undefined)
*** Exception: Prelude.undefined
Run Code Online (Sandbox Code Playgroud)
Chr*_*est 26
我相信这是一个严格的注释.
Haskell是一种纯粹而懒惰的函数式语言,但有时懒惰的开销可能过多或浪费.因此,为了解决这个问题,您可以要求编译器完全评估函数的参数,而不是解析thunk周围的问题.
此页面上有更多信息:Performance/Strictness.