$之间有什么区别! (美元感叹号)和!(感叹号)

时间:2015-03-17 08:08:46

标签: haskell

https://stackoverflow.com/a/2787560/645703说:

  

($!)是严格的功能应用程序。也就是说,它评估了   在评估函数之前的参数。

我知道!(感叹号)是Haskell中的严格声明。看起来两者都有严格应用的东西,但有什么区别?

2 个答案:

答案 0 :(得分:2)

!扩展程序启用的

BangPatterns始终采用模式,在绑定之前,如下所示:

add :: Int -> Int -> Int
add !a b = a + b

这意味着"如果执行试图强制执行此模式案例,则在评估模式的右侧之前将!-ed绑定减少为弱头正常形式"

f $! x表示"如果执行试图强迫这个" f $! X"表达,然后通过首先减少" x"弱头正常形式,然后应用" f"减少" x" &#34 ;.

在这两种情况下,请注意严格注释仅表示条件语句。如果我有一个f $! x(其中x可能是一个复杂计算的thunk),如果执行从未尝试强制f $! x,那么当然没有任何内容会被评估。

答案 1 :(得分:1)

如果传递undefined会导致异常,则会被视为“严格”,如:

> :set -XBangPatterns
> let foo b x = if b then show x else "ignore x"
> let foo' b !x = if b then show x else "ignore x"
> foo False undefined
"ignore x"
> foo' False undefined
"*** Exception: Prelude.undefined

但我们不能在函数声明之外使用!。因此,我们需要使用$!,就像您提供的链接中的示例一样(在这种情况下,它用于替换$):

> const 1 $ undefined
1
> const 1 $! undefined
*** Exception: Prelude.undefined

您还会注意到,对于!,您需要使用BangPatterns语言扩展,但不能使用$!。注意$!是以!实现的(虽然以一种有点奇怪的方式引用我认为必须是issue #2273),这也很有用。

请参阅$! implementation in Prelude

($!)    :: (a -> b) -> a -> b
f $! x  = let !vx = x in f vx  -- see #2273