GHC has a few built-in funcions with special behaviour,
described in this section. All are exported by
GHC.Exts
.
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
.
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.