7.8. Pragmas

GHC supports several pragmas, or instructions to the compiler placed in the source code. Pragmas don't normally affect the meaning of the program, but they might affect the efficiency of the generated code.

Pragmas all take the form {-# word ... #-} where word indicates the type of pragma, and is followed optionally by information specific to that type of pragma. Case is ignored in word. The various values for word that GHC understands are described in the following sections; any pragma encountered with an unrecognised word is (silently) ignored.

7.8.1. DEPRECATED pragma

The DEPRECATED pragma lets you specify that a particular function, class, or type, is deprecated. There are two forms.

You can suppress the warnings with the flag -fno-warn-deprecations.

7.8.2. INLINE and NOINLINE pragmas

These pragmas control the inlining of function definitions.

7.8.2.1. INLINE pragma

GHC (with -O, as always) tries to inline (or “unfold”) functions/values that are “small enough,” thus avoiding the call overhead and possibly exposing other more-wonderful optimisations. Normally, if GHC decides a function is “too expensive” to inline, it will not do so, nor will it export that unfolding for other modules to use.

The sledgehammer you can bring to bear is the INLINE pragma, used thusly:

key_function :: Int -> String -> (Bool, Double)

#ifdef __GLASGOW_HASKELL__
{-# INLINE key_function #-}
#endif

(You don't need to do the C pre-processor carry-on unless you're going to stick the code through HBC—it doesn't like INLINE pragmas.)

The major effect of an INLINE pragma is to declare a function's “cost” to be very low. The normal unfolding machinery will then be very keen to inline it.

Syntactially, an INLINE pragma for a function can be put anywhere its type signature could be put.

INLINE pragmas are a particularly good idea for the then/return (or bind/unit) functions in a monad. For example, in GHC's own UniqueSupply monad code, we have:

#ifdef __GLASGOW_HASKELL__
{-# INLINE thenUs #-}
{-# INLINE returnUs #-}
#endif

See also the NOINLINE pragma (Section 7.8.2.2).

7.8.2.2. NOINLINE pragma

The NOINLINE pragma does exactly what you'd expect: it stops the named function from being inlined by the compiler. You shouldn't ever need to do this, unless you're very cautious about code size.

NOTINLINE is a synonym for NOINLINE (NOINLINE is specified by Haskell 98 as the standard way to disable inlining, so it should be used if you want your code to be portable).

7.8.2.3. Phase control

Sometimes you want to control exactly when in GHC's pipeline the INLINE pragma is switched on. Inlining happens only during runs of the simplifier. Each run of the simplifier has a different phase number; the phase number decreases towards zero. If you use -dverbose-core2core you'll see the sequence of phase numbers for successive runs of the simpifier. [NB: (a) the very first phase is called "gentle" and ignores all rules and pragmas; (b) the simplifier often runs more than once before decreasing the phase number, and these iterations are visible when you use -dverbose-core2core.]

In an INLINE pragma you can optionally specify a phase number, thus:

  • You can say "inline f in Phase 2 and all subsequent phases":
      {-# INLINE [2] f #-}

  • You can say "inline g in all phases up to, but not including, Phase 3":
      {-# INLINE [~3] g #-}

  • If you omit the phase indicator, you mean "inline in all phases".

You can use a phase number on a NOINLINE pragma too:

  • You can say "do not inline f until Phase 2; in Phase 2 and subsequently behave as if there was no pragma at all":
      {-# NOINLINE [2] f #-}

  • You can say "do not inline g in Phase 3 or any subsequent phase; before that, behave as if there was no pragma":
      {-# NOINLINE [~3] g #-}

  • If you omit the phase indicator, you mean "never inline this function".

The same phase-numbering control is available for RULES (Section 7.9).

7.8.3. LINE pragma

This pragma is similar to C's #line pragma, and is mainly for use in automatically generated Haskell code. It lets you specify the line number and filename of the original code; for example

{-# LINE 42 "Foo.vhs" #-}

if you'd generated the current file from something called Foo.vhs and this line corresponds to line 42 in the original. GHC will adjust its error messages to refer to the line/file named in the LINE pragma.

7.8.4. OPTIONS pragma

The OPTIONS pragma is used to specify additional options that are given to the compiler when compiling this source file. See Section 4.1.2 for details.

7.8.5. RULES pragma

The RULES pragma lets you specify rewrite rules. It is described in Section 7.9.

7.8.6. SPECIALIZE pragma

(UK spelling also accepted.) For key overloaded functions, you can create extra versions (NB: more code space) specialised to particular types. Thus, if you have an overloaded function:

hammeredLookup :: Ord key => [(key, value)] -> key -> value

If it is heavily used on lists with Widget keys, you could specialise it as follows:

{-# SPECIALIZE hammeredLookup :: [(Widget, value)] -> Widget -> value #-}

A SPECIALIZE pragma for a function can be put anywhere its type signature could be put.

A SPECIALIZE has the effect of generating (a) a specialised version of the function and (b) a rewrite rule (see Section 7.8.5) that rewrites a call to the un-specialised function into a call to the specialised one. You can, instead, provide your own specialised function and your own rewrite rule. For example, suppose that:
  genericLookup :: Ord a => Table a b   -> a   -> b
  intLookup     ::          Table Int b -> Int -> b
where intLookup is an implementation of genericLookup that works very fast for keys of type Int. Then you can write the rule
  {-# RULES "intLookup" genericLookup = intLookup #-}
(see Section 7.9.4). It is Your Responsibility to make sure that intLookup really behaves as a specialised version of genericLookup!!!

An example in which using RULES for specialisation will Win Big:
  toDouble :: Real a => a -> Double
  toDouble = fromRational . toRational

  {-# RULES "toDouble/Int" toDouble = i2d #-}
  i2d (I# i) = D# (int2Double# i) -- uses Glasgow prim-op directly
The i2d function is virtually one machine instruction; the default conversion—via an intermediate Rational—is obscenely expensive by comparison.

7.8.7. SPECIALIZE instance pragma

Same idea, except for instance declarations. For example:
instance (Eq a) => Eq (Foo a) where { 
   {-# SPECIALIZE instance Eq (Foo [(Int, Bar)]) #-}
   ... usual stuff ...
 }
The pragma must occur inside the where part of the instance declaration.

Compatible with HBC, by the way, except perhaps in the placement of the pragma.

7.8.8. UNPACK pragma

The UNPACK indicates to the compiler that it should unpack the contents of a constructor field into the constructor itself, removing a level of indirection. For example:

data T = T {-# UNPACK #-} !Float
           {-# UNPACK #-} !Float

will create a constructor T containing two unboxed floats. This may not always be an optimisation: if the T constructor is scrutinised and the floats passed to a non-strict function for example, they will have to be reboxed (this is done automatically by the compiler).

Unpacking constructor fields should only be used in conjunction with -O, in order to expose unfoldings to the compiler so the reboxing can be removed as often as possible. For example:

f :: T -> Float
f (T f1 f2) = f1 + f2

The compiler will avoid reboxing f1 and f2 by inlining + on floats, but only when -O is on.

Any single-constructor data is eligible for unpacking; for example

data T = T {-# UNPACK #-} !(Int,Int)

will store the two Ints directly in the T constructor, by flattening the pair. Multi-level unpacking is also supported:

data T = T {-# UNPACK #-} !S
data S = S {-# UNPACK #-} !Int {-# UNPACK #-} !Int

will store two unboxed Int#s directly in the T constructor. The unpacker can see through newtypes, too.

If a field cannot be unpacked, you will not get a warning, so it might be an idea to check the generated code with -ddump-simpl.

See also the -funbox-strict-fields flag, which essentially has the effect of adding {-# UNPACK #-} to every strict constructor field.