1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
|
%**<title>A Gentle Introduction to Haskell: Typing Pitfalls</title>
%**~header
\section{Typing Pitfalls}
This short section give an intuitive description of a few common
problems that novices run into using Haskell's type system.
\subsection{Let-Bound Polymorphism}
Any language using the Hindley-Milner type system has what is called
{\em let-bound polymorphism}, because identifiers not bound using a
@let@ or @where@ clause (or at the top level of a module) are limited
with respect to their polymorphism. In particular, a {\em
lambda-bound} function (i.e., one passed as argument to another
function) cannot be instantiated in two different ways. For example,
this program is illegal:
\bprog
@
let f g = (g [], g 'a') -- ill-typed expression
in f (\x->x)
@
\eprog
because @g@, bound to a lambda abstraction whose principal type is
@a->a@, is used within @f@ in two different ways: once with type
@[a]->[a]@, and once with type @Char->Char@.
\subsection{Numeric Overloading}
It is easy to forget at times that numerals are {\em overloaded,} and
{\em not implicitly coerced} to the various numeric types, as in many
other languages. More general numeric expressions sometimes cannot be
quite so generic. A common numeric typing error is something like the
following:
\bprog
@
average xs = sum xs / length xs -- Wrong!
@
\eprog
@(/)@ requires fractional arguments, but @length@'s result is
an @Int@. The type mismatch must be corrected with an explicit coercion:
\bprog
@
average :: (Fractional a) => [a] -> a
average xs = sum xs / fromIntegral (length xs)
@
\eprog
\subsection{The Monomorphism Restriction}
The Haskell type system contains a restriction related to type classes
that is not found in ordinary Hindley-Milner type systems: the {\em
monomorphism restriction}. The reason for this restriction is related
to a subtle type ambiguity and is explained in full detail in the
Report (\see{sect:monomorphism-restriction}). A simpler explanation
follows:
The monomorphism restriction says that any identifier bound by a
pattern binding (which includes bindings to a single identifier), and
having no explicit type signature, must be {\em monomorphic}. An
identifier is monomorphic if is either not overloaded, or is
overloaded but is used in at most one specific overloading and is not
exported.
Violations of this restriction result in a static type error. The
simplest way to avoid the problem is to provide an explicit type
signature. Note that {\em any} type signature will do (as long it is
type correct).
A common violation of the restriction happens with functions defined
in a higher-order manner, as in this definition of @sum@ from the
Standard Prelude:
\bprog
@
sum = foldl (+) 0
@
\eprog
As is, this would cause a static type error. We can fix the problem
by adding the type signature:
\bprog
@
sum :: (Num a) => [a] -> a
@
\eprog
Also note that this problem would not have arisen if we had written:
\bprog
@
sum xs = foldl (+) 0 xs
@
\eprog
because the restriction only applies to pattern bindings.
%**~footer
|