Haskell声明中的惊叹号是什么意思?
我试图通过一个真正的项目来学习Haskell来驱动它,我遇到了以下定义。 我不明白每个争论前面的惊叹号是什么意思,我的书似乎没有提到它。
data MidiMessage = MidiMessage !Int !MidiMessage
这是一个严格的声明。 基本上,这意味着当创建数据结构值时,必须对所谓的“弱正常头部形式”进行评估。 我们来看一个例子,以便我们看到这意味着什么:
data Foo = Foo Int Int !Int !(Maybe Int)
f = Foo (2+2) (3+3) (4+4) (Just (5+5))
上面的函数f
在评估时会返回一个“thunk”:即要执行的代码来计算其值。 那时,Foo甚至还不存在,只是代码。
但是在某些时候,有人可能会试着去关注它,可能是通过模式匹配:
case f of
Foo 0 _ _ _ -> "first arg is zero"
_ -> "first arge is something else"
这将执行足够的代码来执行它所需的操作,而不会再执行任何操作。 所以它会创建一个带有四个参数的Foo(因为如果没有这个参数,你就无法查看它)。 首先,由于我们正在测试它,所以我们需要评估一直到4
,我们意识到它不匹配。
第二个不需要评估,因为我们没有对它进行测试。 因此,而不是6
被存储在该存储单元中,我们只存储可能以后评估的代码, (3+3)
只有当有人看着它时,它才会变成6。
然而,第三个参数有一个!
在它之前,严格地评估: (4+4)
被执行,并且8
被存储在该存储器位置中。
第四个参数也被严格评估。 但是,这里有点棘手:我们不是完全评估,而只是对弱的正常头部形式。 这意味着我们要弄清楚它是Nothing
或Just
某种东西,并且存储它,但我们不会再进一步。 这意味着我们不仅仅存储Just 10
而且实际上Just (5+5)
,使得thunk内部未被评估。 这一点很重要,但我认为这个问题的所有影响都超出了这个问题的范围。
如果启用BangPatterns
语言扩展,您可以用相同的方式注释函数参数:
f x !y = x*y
f (1+1) (2+2)
将返回thunk (1+1)*4
。
查看严格构造函数参数与非严格构造函数参数之间区别的一种简单方法是,它们在未定义时的行为方式。 特定
data Foo = Foo Int !Int
first (Foo x _) = x
second (Foo _ y) = y
由于非严格参数不是以second
为单位进行评估,因此传入undefined
不会导致问题:
> second (Foo undefined 1)
1
但严格的参数不能被undefined
,即使我们不使用该值:
> first (Foo 1 undefined)
*** Exception: Prelude.undefined
我相信这是一个严格的标注。
Haskell是一种纯粹而懒惰的函数式语言,但有时懒惰的开销可能太多或浪费。 所以为了解决这个问题,你可以要求编译器完全评估函数的参数,而不是解析周围的东西。
本页有更多信息:性能/严格性。
链接地址: http://www.djcxy.com/p/42935.html上一篇: What does the exclamation mark mean in a Haskell declaration?
下一篇: Which parts of Real World Haskell are now obsolete or considered bad practice?