File: pitfalls.verb

package info (click to toggle)
haskell98-tutorial 200006-2-3
  • links: PTS
  • area: main
  • in suites: bullseye
  • size: 972 kB
  • sloc: haskell: 2,125; makefile: 68; sh: 9
file content (95 lines) | stat: -rw-r--r-- 3,195 bytes parent folder | download | duplicates (6)
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