4.2 Overloading

Haskell uses typeclasses to methodically allow overloading. A
typeclass describes a set of functions, and any type which provides
those functions can be made an instance of that type. This avoids
the syntactic redundancy of languages like OCaml.

For example, the function

*

is a method of the typeclass

Num

, as we can see from its type:

Prelude> :t (*)(*)::(Num a)=> a -> a -> a

Which can be read as "* is a polymorphic function, taking two types 'a',
and returning a result of the same type, where those types are members
of the class Num".

This means that it will operate on any type in the

Num

class, of which the following types are members:

Double,Float,Int,Integer

. Thus:

Prelude>2.3*5.713.11

or on integers:

Prelude>2*510

The type of the arguments determines which instance of

*

is

used. Haskell also never performs implicit coercions, all coercions must
be explicit. For example, if we try to multiply two different types,

Why bother -- why not allow the system to implicitly coerce types?
Implicit type conversions by the system are the source of innumerable
hard to find bugs in languages that support them, and makes reasoning
about a program harder, since you must apply not just the language's
semantics, but an extra set of coercion rules.

Note that If we leave off the type signatures however, Haskell will
helpfully infer the most general type:

Prelude>2.3*511.5

4.3 Expressions

In Haskell expressions are everything. There are no pure "statements"
like in Java/C++. instead, statements are also expressions, they return
values.

Prelude>(if2==3then5else6)+17

Prelude>(if2==3then5else6.5)+17.5

4.4 Local bindings

In Haskell

let

allows local declarations to be defined.

let x =1+2in x +3

is analogous to:

{
int x = 1 + 2;
... x + 3 ... ;
}

in C, but the Haskell variable x is given a value that is immutable (can
never change).

4.5 Allocation

When you declare a new variable, Haskell automatically allocates that
value for you -- no need to explicitly manage memory. The garbage
collector will then collect any ureachable values once they go out of
scope.

Advanced users can also manage memory by hand using the foreign function
interface.

4.6 Lists

Lists are ... lists of Haskell values. Defining a new list is trivial,
easier than in Java.

Prelude>[2,1+2,4][2,3,4]
Prelude> :t [2,1+2,4][2,1+2,4]::(Num a)=>[a]

This automatically allocates space for the list and puts in the elements.
Haskell is garbage-collected like Java so no explicit de-allocation is
needed. The type of the list is inferred automatically. All elements of
a list must be of the same type.

Prelude>["e",concat["f","g"],"h"]["e","fg","h"]

Notice how the function call

concat["f","g"]

does not require

parenthesis to delimit the function's arguments. Haskell
uses whitespace, and not commas, and:

You don't need parentheses for function application in Haskell:

sin0.3

Multiple arguments can be passed in one at a time (curried) which means they can be separated by spaces:

max34

.

Lists must be uniform in their type ("homogenous").

Prelude>['x', True]
Couldn't match `Char' against `Bool'

Here we tried to build a list containing a Char and a Boolean, but the

list constructor,

[]

, has type:

Prelude> :t [][]::[a]

meaning that all elements must be of the same type,

a

.

(For those wondering how to build a list of heterogenous values, you
would use a sum type):

4.7 Pattern matching

Haskell supports pattern matching on data structures. This is a powerful
language feature, making code that manipulates data structures
incredibly simple. The core language feature for pattern matching is the

case

expression:

Prelude>case x of h:t -> h
2

The

case

forces

x

(the scrutinee) to match
pattern

h:t

, a list with head and tail, and then we extract
the head,

h

. Tail is similar, and we can use a wildcard

pattern to ignore the part of the pattern we don't care about:

Prelude>case x of_:t -> t
[3]

4.8 Tuples

Tupes are fixed length structures, whose fields may be of differing
types ("heterogenous"). They are known as product types in
programming language theory.

Prelude>let x =(2,"hi")
Prelude>case x of(y,_)-> y
2

Unlike the ML family of languages, Haskell uses the same syntax for the
value level as on the type level. So the type of the above tuple is:

Prelude> :t x
x ::(Integer,[Char])

All the data mentioned so far is immutable - it is impossible to change
an entry in an existing list, tuple, or record without implicitly
copying the data! Also, all variables are immutable.
By default Haskell is a pure language. Side effects, such as
mutation, are discussed later.

specially tag it as such, as you would in the ML family of languages).

When you apply (or invoke) the fac function, you don't need any
special parenthesis around the code. Note that there is no return
statement; instead, the value of the whole body-expression is implicitly
what gets returned.

Functions of more than one argument may be defined:

Prelude>letmax a b =if a > b then a else b
Prelude>max377

Other important aspects of Haskell functions:

Functions can be defined anywhere in the code via lambda abstractions:

Prelude>((\x -> x +1)4)+712

Or, identical to

let f x = x +1

:

Prelude>let f = \x -> x +1
Prelude> :t f
f ::Integer->Integer

Anonymous functions like this can be very useful. Also, functions can
be passed to and returned from functions. For example, the higher order

function

map

, applies its function argument to each

element of a list (like a for-loop):

Prelude>map(\x -> x ^2)[1..10][1,4,9,16,25,36,49,64,81,100]

In Haskell, we can use section syntax for more concise anonymous
functions:

Prelude>map(^2)[1..10][1,4,9,16,25,36,49,64,81,100]

Here

map

takes two arguments, the function </hask>(^

2) :: Integer -> Integer</hask>, and a list of numbers.

5.1 Currying

Currying is a method by which function arguments may be passed one at a
time to a function, rather than passing all arguments in one go in a
structure:

5.4 Higher order functions

Haskell, like ML, makes wide use of higher-order functions: functions
that either take other functions as argument or return functions as
results, or both. Higher-order functions are an important component of a
programmer's toolkit.

They allow "pluggable" programming by passing in and out chunks of code.

The lower case variables in the type declaration of map are type
variables, meaning that the function is polymorphic in that
argument (can take any type).

Prelude>map(*10)[4,2,7][40,20,70]

Perhaps the simplest higher-order function is the composer, in
mathematics expressed as g o f. it takes two functions and returns a
new function which is their composition:

(.)::(b -> c)->(a -> b)-> a -> c
(.) f g x = f (g x)

This function takes three arguments: two functions, f and g, and
a value, x. It then applies g to x, before applying f to
the result. For example:

Prelude>let plus3times2 =(*2).(+3)
Prelude> plus3times2 1026

As we have seen before, functions are just expressions so can also be
immediately applied after being defined:

Prelude>((*2).(+3))1026
Prelude>(.)(*2)(+3)1026

Note how Haskell allows the infix function . to be used in prefix
form, when wrapped in parenthesis.

5.5 Currying

Currying is an important concept of functional programming; it is named
after logician Haskell Curry,
after which the languages Haskell and Curry are named! Multi-argument
functions as defined thus far are curried, lets look at what is really
happening.

Here is a two-argument function defined in our usual manner.

Prelude>let myadd x y = x + y
Prelude> myadd 347

Here is another completely equivalent way to define the same function:

With currying, all functions "really" take exactly one argument.
Currying also naturally arises when functions return functions, as in
the map application above showed. Multiple-argument functions should
always be written in curried form; all the library functions are
curried.

Note thus far we have curried only two-argument functions; in general,
n-argument currying is possible. Functions can also take pairs as
arguments to achieve the effect of a two-argument function:

Prelude>let mypairadd (x,y)= x + y
Prelude> mypairadd (2,3)5

So, either we can curry or we can pass a pair. We can also write
higher-order functions to switch back and forth between the two forms.

This function also illustrates how functions may be defined in a local scope,

using

where

. Observe 'go' is defined locally but then exported

since it is the return value of f.

Question: How does the return value 'go' know where to look for k when its called??

Prelude>let summate =foldr(+)
Prelude> summate [1,2,3,4]010

summate

is just

go

but somehow it "knows" that k is

(+)

, even though k is undefined at the top level:

Prelude> k
<interactive>:1:0: Not in scope: `k'

go

in fact knew the right k to call, so it must have been kept

somewhere: in a closure. At function definition point, the current values
of variables not local to the function definition are remembered in a structure
called a closure. Function values in Haskell are thus really a pair consisting
of the function (pointer) and the local environment, in a closure.

Without making a closure, higher-order functions will do awkward things (such
as binding to whatever 'k' happens to be in scope). Java, C++, C can pass and
return function (pointers), but all functions are defined at the top level so
they have no closures.

5.8 Loading source from a file

You should never type large amounts of code directly into GHCi! Its impossible
to fix errors. Instead, you should edit in a file. Usingg any editor, save each
group of interlinked functions in a separate file, for example "A.hs". Then,
from GHCi type:

6.4 Parametric polymorphism

The form of polymorphism in Haskell is to be precise, parametric polymorphism. The type above is parametric in t: what comes out is the same type as what came in. Generics is another term for parametric polymorphism used in some communities.

Java has no parametric polymorphism, but does have object polymorphism (unfortunately this is often just called polymorphism by some writers) in that a subclass object can fit into a superclass-declared variable.

When you want parametric polymorphism in Java you declare the variable to be of type Object, but you have to cast when you get it out which requires a run-time check.

The Java JDK version 1.5 will have parametrically polymorphic types in it.

The general intuition to have about the type inference algorithm is everything
starts out as having arbitrary types, t, u, etc, but then the use of functions
on values generates constraints that "this thing has the same type as that
thing".

When a function is defined via let to have polymorphic type, every use can be at a different type:

letid x = x
incaseid True of
True ->id3
False ->id43

6.5 Algebraic Data Types

Algebraic data types in Haskell are the analogue of union/variant types in
C/Pascal. Following in the Haskell tradition of lists and tuples, they are not
mutable. Haskell data types must be declared. Here is a really simple algebraic
data type declaration to get warmed up, remember to write this in a separate
file, and load it in to HHCi:

data Height = Tall | Medium | Short

Three constructors have been defined. These are now official constants.
Constructors must be capitalized, and variables must be lower-case in Haskell.