haskelltypesfunctional-programmingghcparsec

What does the ! do in record syntax in Haskell?


I was reading through some of the Parsec source code. In the definition of State s u, shown below, I noticed some syntax I was not familiar with.

data State s u = State {
  stateInput :: s,
  statePos   :: !SourcePos,
  stateUser  :: !u
}
deriving ( Typeable )

What does the "!" signify in this context? This page defines the ! operator as,

Force evaluation (strictness flag)

My best guess is that the "!" stops lazy evaluation for certain variables. Is this correct? Can "!" be used outside of records in Haskell? If it makes a difference, I am specifically wondering about how GHC handles "!".


Solution

  • Under normal circumstances, the bare function State is short for \a b c -> State a b c. If there are exclamation points, each adds in a seq; so your declaration means that State is actually short for \a b c -> b `seq` c `seq` State a b c. This is not special to record syntax; it can also be used with non-record data declarations.

    Besides data declarations, the BangPatterns language extension allows the use of ! in patterns to add a seq. The translation is similar; by way of example,

    f a !b !c = {- ... -}
    

    is short for:

    f a b c = b `seq` c `seq` {- ... -}
    

    Note in both cases that all seqs appear only once the application is saturated; i.e. the above two examples are not short for this:

    \a b -> b `seq` \c -> c `seq` State a b c
    f a b = b `seq` \c -> c `seq` {- ... -}
    

    The difference is subtle, but can matter and sometimes surprise you.