GHC has a few built-in funcions with special behaviour,
described in this section. All are exported by
GHC.Exts
.
The function seq
is as described in the Haskell98 Report.
seq :: a -> b -> b
It evaluates its first argument to head normal form, and then returns its
second argument as the result. The reason that it is documented here is
that, despite seq
's polymorphism, its
second argument can have an unboxed type, or
can be an unboxed tuple; for example (seq x 4#)
or (seq x (# p,q #))
. This requires b
to be instantiated to an unboxed type, which is not usually allowed.
The inline
function is somewhat experimental.
inline :: a -> a
The call (inline f)
arranges that f
is inlined, regardless of its size. More precisely, the call
(inline f)
rewrites to the right-hand side of f
's
definition.
This allows the programmer to control inlining from
a particular call site
rather than the definition site of the function
(c.f. INLINE
pragmas Section 7.10.3, “INLINE and NOINLINE pragmas”).
This inlining occurs regardless of the argument to the call
or the size of f
's definition; it is unconditional.
The main caveat is that f
's definition must be
visible to the compiler. That is, f
must be
let-bound in the current scope.
If no inlining takes place, the inline
function
expands to the identity function in Phase zero; so its use imposes
no overhead.
If the function is defined in another module, GHC only exposes its inlining in the interface file if the function is sufficiently small that it might be inlined by the automatic mechanism. There is currently no way to tell GHC to expose arbitrarily-large functions in the interface file. (This shortcoming is something that could be fixed, with some kind of pragma.)
The lazy
function restrains strictness analysis a little:
lazy :: a -> a
The call (lazy e)
means the same as e
,
but lazy
has a magical property so far as strictness
analysis is concerned: it is lazy in its first argument,
even though its semantics is strict. After strictness analysis has run,
calls to lazy
are inlined to be the identity function.
This behaviour is occasionally useful when controlling evaluation order.
Notably, lazy
is used in the library definition of
Control.Parallel.par
:
par :: a -> b -> b par x y = case (par# x) of { _ -> lazy y }
If lazy
were not lazy, par
would
look strict in y
which would defeat the whole
purpose of par
.
Like seq
, the argument of lazy
can have
an unboxed type.
The function unsafeCoerce#
allows you to side-step the
typechecker entirely. It has type
unsafeCoerce# :: a -> b
That is, it allows you to coerce any type into any other type. If you use this function, you had better get it right, otherwise segmentation faults await. It is generally used when you want to write a program that you know is well-typed, but where Haskell's type system is not expressive enough to prove that it is well typed.
The argument to unsafeCoerce#
can have unboxed types,
although extremely bad things will happen if you coerce a boxed type
to an unboxed type.