|CS 331 Spring 2013 > Lecture Notes for Wednesday, February 20, 2013|
To define an ordinary function in Haskell,
give the function’s name, followed by
parameter names, all separated by blanks,
then an equals sign (“
and an expression giving the return value of the function.
[Haskell]addem a b = a+b
A function call looks much like the part of the definition before the equals sign.
[Interactive Haskell]> addem 4 10 14
Haskell also allows the definition of new binary infix operators.
The name of an infix operator must consist of a sequence of one
or more of the following twenty symbols,
and it must not begin with a colon (“
! # $ % & * + . / < = > ? @ \ ^ | - ~ :
Here is a definition:
[Haskell]a +$+ b = 2*(a+b)
And a call:
[Interactive Haskell]> 7 +$+ 1 16
Precedence and associativity can be set (look it up if you are interested).
Haskell functions and operators may be callable on
This is handled a bit like C++ templates, but with
stricter type checking.
For example, look at the type of function
[Interactive Haskell]> :t addem addem :: Num a => a -> a -> a
The part at the right, “
a -> a -> a”,
addem is a function that takes
two parameters of the same type
and returns a value of that same type.
The earlier part, “
Num a =>”,
a must be a numeric type.
[Interactive Haskell]> addem 1 2 3 > addem 1.2 2.3 3.5 > addem "abc" "def" -- Not numeric ERROR ...
Num is an example of a Haskell type class,
a collection of types that all support a common interface.
Every type in type class
supports equality testing, addition, subtraction,
(but not necessarily division;
there is no built-in integer division operator in Haskell,
div does integer division).
The above facility for calling the same function with different types still executes the same code for each type. Haskell does support function and operator overloading in a way that allows for different code to be executed for different types. This is part of the type class concept; we will not discuss this now.
Function application in Haskell is an invisible operator. This operator has high precedence, and it is left-associative.
[Interactive Haskell]> addem 1 7 8 > (addem 1) 7 8 > addem (1 7) ERROR ...
In the first two lines above,
(addem 1) is actually a function,
which is applied to
addem is really a function that returns a function.
addem the argument
and it returns a function that adds 1 to things.
7 to that function,
and the result is
This is called currying (after Haskell Curry again).
The reality is that every Haskell function has
exactly one argument.
We can simulate functions with two (or more) arguments
using a function that returns a function.
a -> a -> a”
that we saw above
a -> (a -> a)”:
the function takes an
and returns another function,
which takes an
a and returns an
First-class values generally do not have to be named.
For example suppose we wish to output
In C++, we can give this a name:
[C++]int sum = 3+4; // The name is "sum" cout << sum << endl;
Or we can leave it unnamed:
[C++]cout << 3+4 << endl;
C++ traditionally does not allow for unnamed functions
(although C++11 has them).
In Haskell, a function is an ordinary value;
unnamed functions are common.
Indeed, we have already seen one:
A general syntax for making unnamed functions is
a lambda expression.
This begins with a backslash
it looks a bit like a Greek lambda (“λ”).
Next come parameter names,
an arrow (“
and an expression for the return value of the function.
For example, here is the definition of a function to square a number.
[Haskell]square x = x*x
Here it is as a lambda expression.
[Haskell]\ x -> x*x
Both of these can be used.
[Interactive Haskell]> square 5 25 > (\ x -> x*x) 5 25
These means we could define a square function two different ways:
[Haskell]square x = x*x square' = \ x -> x*x
Indeed, the first form above is essentially just shorthand for the second (without the “prime”).
We can also define
addem in this way.
[Haskell]addem = \ x y -> x+y
But remember currying.
addem really has just one parameter,
and it returns a function:
[Haskell]addem a = \ y -> a+y
[Haskell]addem = \ x -> (\ y -> x+y)
Lambda functions allow us to do some things more concisely.
[Haskell]square x = x*x sqlist = map square [1,2,3,4] -- sqlist is [1,4,9,16]
[Haskell]sqlist = map (\ x -> x*x) [1,2,3,4] -- sqlist is [1,4,9,16]
A higher-order function
is a function that deals with functions.
For example, here is the definition of a higher-order function
[Haskell]rev f a b = f b a
rev as a one-argument function.
It takes a two-argument function,
and returns another one with its arguments reversed.
[Haskell]sub a b = a-b rsub = rev sub
Now the value of
rsub x y is
for Haskell source code related to today’s lecture.