3

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

($!) is strict function application. That is, it evaluates the argument before evaluating the function.

I know !(exclamation point) is a strictness declaration in Haskell. It looks like both both have something with strict application, but what is the difference?

Community
  • 1
  • 1
Matt Elson
  • 4,177
  • 8
  • 31
  • 46

2 Answers2

2

! as enabled by the BangPatterns extension is always in a pattern, before a binding, like this:

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

It means "if execution tries to force this pattern case, then reduce the !-ed binding to weak head normal form before evaluating the right hand side of the pattern"

f $! x means "if execution tries to force this "f $! x" expression, then proceed by first reducing "x" to weak head normal form, then applying "f" to the reduced "x" ".

In both cases, note that the strictness annotations only express a conditional statement. If I have a f $! x lying around (where x might be a thunk for a complicated computation), if the execution never tries to force f $! x, then of course nothing of it will be evaluated.

András Kovács
  • 29,931
  • 3
  • 53
  • 99
  • 1
    Actually, `!` can also appear in datatype declarations, to denote that a constructor function should be strict (to WHNF) in a particular argument. The use in datatype definitions also predates the appearance of "bang patterns". – kosmikus Mar 17 '15 at 09:36
  • what is the difference between add !a b=a+b and add $! a b=a+b ? please give some explanations. – Matt Elson Mar 17 '15 at 10:12
  • @MattElson: there is no difference, both are syntax errors. You can do `ghci -XBangPatterns`, then it will accept `let add (!a) b = a + b`, but you cannot `let add $! a b = a + b`. – d8d0d65b3f7cf42 Mar 17 '15 at 10:34
  • "...then reduce the !-ed binding to weak head normal form before evaluating the right hand side of the pattern", what is the right hand side of the pattern in the definition of add? I guess it is the first parameter a. – Matt Elson Mar 17 '15 at 14:01
  • @MattElson by right hand side I mean on the right of "=", namely "a + b" there – András Kovács Mar 17 '15 at 14:09
1

Something is considered "strict" when it would lead to an exception if passed undefined, as in:

> :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

But we can't use ! outside of function declarations. So instead we need to use $! as in the example in the link you provided (in this case it is used to replace $):

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

You'll notice also that for ! you need to use the BangPatterns language extension but you don't for $!. It's also useful to note that $! is implemented in terms of ! (though in a slightly weird way and refers to what I guess must be issue #2273).

See the $! implementation in Prelude:

($!)    :: (a -> b) -> a -> b
f $! x  = let !vx = x in f vx  -- see #2273
TheCriticalImperitive
  • 1,457
  • 1
  • 10
  • 23
  • If I understand you correctly: ! is a strictness declaration, so the parameter after ! will be evaluated to weak head normal form(WHNF). $! is strict function application, and it will first evaluate the argument to weak head normal form, and then apply the function. If I am wrong please correct me. – Matt Elson Mar 17 '15 at 11:10