Haskell Tutorial
Adapted from A Gentle Introduction to Haskell and Haskell-Tutorial by Jerry James and Vicki Allan.
This tutorial is intended as a self-help guide. If you get lost using it, take note of your problems and let me know so I can make it clearer.
Getting Started
If you are using HUGS (recommended), then familiarize yourself with the environment by working through the examples in the getting started document. If you are using GHC, then read Chapter 3 of the GHC User's Guide.
Introduction
This tutorial teaches you about the Haskell language as defined in the Haskell98 specification. Haskell is a “typeful” programming language (the term typeful was coined by Luca Cardelli). Types are pervasive, and the newcomer is best off becoming well aware of the full power and complexity of Haskell's type system from the outset. For those whose only experience is with relatively “untypeful” languages such as Perl, Tcl, or Scheme, this may be a difficult adjustment; for those familiar with Java, C, Modula, or even ML, the adjustment should be easier but still not insignificant, since Haskell's type system is different and somewhat richer than most. In any case, “typeful programming” is part of the Haskell programming experience, and cannot be avoided.
Hello, World!
I/O is not Haskell's strong point, but let's get started with the (infamous?) "Hello, world!" example. Create a file called HelloWorld.hs (hs stands for “Haskell script”) containing the following code:
{- HelloWorld.hs This is a multiline comment. -} -- This is a single-line comment. hello :: IO () hello = putStrLn "Hello, world!"
Load this file into your interpreter. Then evaluate the expression
hello to invoke the function. Does it do what you
expect?
We can learn several bits of Haskell syntax from this example.
First, we now know how to write both multiline and single-line
comments. The first line of actual code is the equivalent of a C++
function prototype: it gives the types of the parameters and the
return value of the hello function. In this case, there
are no parameters, and IO () is the return type. We will
explain later what this means. Finally, the function itself is
defined using an assignment operator. This operator binds
the definition to the name hello. Since only the
function name occurs to the left of the assignment operator, this
function takes no parameters.
Now edit this file and remove the type declaration for
hello. Load the revised version into your interpreter
and invoke the hello function again. It still works!
Haskell does not need most type declarations. It can figure out the
appropriate types itself using a type inference algorithm; in
fact, it is the algorithm we discussed in class in conjunction with the
Hindley-Milner type system. Nevertheless, the type declarations often
contribute toward good code documentation.
Types
Every expression has an associated type:
42 :: Integer -- An unbounded integer 'a' :: Char -- A Unicode character [1,2,3] :: [Integer] -- A list of integers ('b',4) :: (Char,Integer) -- A tuple in which the first component is a Char -- and the second component is an Integer
What should the type of a function be? It should at least convey the
fact that it takes values of one type (say T1) and
returns values of (possibly) some other type (say T2).
In Haskell, this is written T1 -> T2 and we say that
such a function maps values of type T1 to values of type
T2. Functions with multiple parameters use more arrows.
For example, a function with parameters of types Integer
and Char, respectively, and returning
(Integer,Char) has type Integer -> Char ->
(Integer,Char).
Writing Functions in Haskell
In a functional language, everything (even a program) is a function. Thus, writing a program is actually writing a function. You can write many functions in a single file; that is, you can have many programs in a single file. Each function then may use other functions to calculate its result. There are many predefined functions available like in other programming languages. These functions are included in the Haskell Prelude and in the Haskell Libraries.
Writing a function consists of two parts. First, we have to define
the types for the arguments and the result. A function may have no
arguments, such as our hello function above. This is
called a constant function. Constant function definitions
have the form:
name :: type name = expression
as in this example:
pi :: Float pi = 3.1415926535
In such declarations, :: is read “is of
type”. Other functions may have one or more arguments.
However, each function has a single result, e.g.:
doubleIt :: Integer -> Integer
The name of our new function is doubleIt. The
:: separates the name of the function from the type
definition. The parameter types are separated from each other and
from the return type by ->. Therefore, the
declaration above reads “doubleIt is a function
with one Integer parameter, returning
Integer.”
The second part of writing a function is the concrete implementation, e.g.:
doubleIt x = 2 * x
Note that the parameters are not in parentheses, as you may
be used to from learning other languages. To test the functionality
of our doubleIt function, we type doubleIt 2
at the Haskell interpreter prompt. What is the result?
Exercise 1: Write a Haskell function
named area to find the circumference of a circle, given
the radius. Note that the Haskell prelude defines pi, so
do not use the definition above or you will get a name conflict.
Let us take another example. Like many programming languages,
Haskell has a predefined data type for Boolean values. An important
operator for Boolean values is the logical and. Although
Haskell already knows that function we will implement it again. One
solution would be to write is in the following way:
and1 :: Bool -> Bool -> Bool and1 a b = if a == b then a else False
Here we use a branch (if-then-else) to split the calculation method
for the result. If the parameters are equal (either both
True or False) we return the value of one of
the parameters. If the parameters are not equal we return
False. Another method would be the use of pattern
matching. The logical and has a special case
where the result is True. In all other cases the result
is False. We know which parameters the special case has.
We can write these parameters in a separate line and give the result.
For all other cases we write a second line:
and2 :: Bool -> Bool -> Bool and2 True True = True and2 x y = False
This says, if the first parameter is True and the second
parameter is True, then return True.
Otherwise, the parameters match the pattern x y; return
False. We did not use the parameters for calculating the
result of the second line. It is not necessary to know the values of
the parameters because we have a constant result. In Haskell we can
write _ instead of providing names for these parameters.
The advantage is that the reader knows the number of parameters, and
also knows that the result is independent of the values of these
parameters. The second line would then look like this:
and2 _ _ = False
Exercise 2: Write a Haskell function
named fib which computes Fibonacci numbers. Recall that
fib 0 == 0, fib 1 == 1, and otherwise
fib n is the sum of fib (n - 1) and
fib (n - 2).
Exercise 3: Write a Haskell function
named avg which computes the average of three integers,
and returns an integer result. Note that `div` performs
integer division.
Exercise 4: Write a Haskell function
named xor that returns True if its 2
parameters are both True or both False, and
returns False if they are different.
Guards
Guards (or conditions)are used to give alternatives. Guards can be used instead of an if-then-else. Guards indicate various cases in the computation.
max :: Int -> Int-> Int max x y | x > y = x | otherwise = y
If the first condition is satisfied, the result is x.
Otherwise, the result is y. Note the guards are
evaluated in order. The first guard that is true controls the
result.
Exercise 5: Write a Haskell function
named max3 that computes the maximum of three values.
Use guards.
Layout
A script contains a series of definitions, one after another. How is it clear when one ends and another begins? It is all done with indentation. Formally, a defintion is ended by the first piece of text which lies at the same indentation or to the left of the start of the definition. This layout rule is much the same as Python's. However, it is optional. Haskell also supports block beginning and ending markers (curly braces) and statement separators (semicolons). In the absence of such punctuation, the layout rules must be followed.
Exercise 6: Try the following function (with strange indentation) to see how Haskell enforces the indentation rule.
max4 :: Int -> Int-> Int max4 x y | x > y = x | otherwise = y
The reader will note that we have capitalized identifiers that denote
specific types, such as Integer and Double,
but not identifiers that denote values. This is not just a
convention: it is enforced by Haskell's lexical syntax. In fact, the
case of the other characters matters, too: foo, fOo, and fOO are all
distinct identifiers.
Exercise 7: Try the following function definition to see how Haskell tells you it doesn't like the capitalization.
And1 :: Bool -> Bool -> Bool And1 a b = if a == b then a else False
Characters
Characters in Haskell are written in single quotes, such as
'a'. The built-in function fromEnum
converts from an enumerated type (such as Char) to an
integer. So, for example, fromEnum 'A' returns 65. The
toEnum function converts an integer to an enumerated type
(such as Char). The following example shows two
functions which together convert a lower case character to upper
case.
offset :: Int offset = fromEnum 'A' - fromEnum 'a' toUpper :: Char -> Char toUpper ch = toEnum (fromEnum ch + offset)
Where and if-then-else
Let us take a more complex example. Consider quadratic equations of
the form a2x2 + a1x +
a0 = 0. The equation has two (possibly equal)
roots. Recall that the formula for solving quadratic equations
is:
x = (-b +/- sqrt(b2 - 4ac)) / 2a
(I would make it look prettier than that, but that would require using MathML, which I suspect is not supported by many of your browsers.) Let us write a function that computes the roots. It will need to take 3 values as inputs and produce two values as outputs. We know how to provide multiple parameters, but how do we return multiple values? As in Python, we pack them into a tuple. Here is the type definition of our function:
roots :: Float -> Float -> Float -> (Float, Float)
Note that the type definition of a tuple is a set of parentheses enclosing a comma-separated list of types.
The next step is the definition of the function
roots:
roots a b c = (x1, x2) where x1 = e + sqrt d / (2 * a) x2 = e - sqrt d / (2 * a) d = b * b - 4 * a * c e = - b / (2 * a)
The result of the function is a pair (x1, x2). Both
values x1 and x2 are defined by local
definitions (after the where clause). The local
definitions calculate parts of the result. In general it is useful to
create a local definition for a partial calculation if the result of
that calculation is needed more than once. The result of the local
definitions d and e, for example, is
necessary for both parts of the solution (x1 and
x2). The solutions themselves could have been written
directly in the tuple. However, defining them as local definitions
improves the readability of the code because the symmetry of the
solution is clearly visible.
This function works for real roots of a quadratic equation, but not
for imaginary roots. We can test that as follows:
Main> roots 1.0 2.0 1.0
(-1.0,-1.0)
Main> roots 1.0 1.0 1.0
(
Program error: argument out of
range
(Note that this is the HUGS response; GHCi instead gives
(NaN,NaN) as the response to the second invocation of
roots, where NaN means
not a number.) The
problem here is that a negative real number is being passed to the
sqrt function.
One way to address the problem is to detect it and tell the user what
is really going on. Try this version of the roots
function:
roots a b c = if d < 0 then error "Cannot solve for complex roots" else (x1, x2) where x1 = e + sqrt d / (2 * a) x2 = e - sqrt d / (2 * a) d = b * b - 4 * a * c e = - b / (2 * a)
This version shows the use of Haskell's if-then-else
construct. The value of an if-then-else is the value of
the then part or the value of the else part,
depending on whether the if part is true or false,
respectively.
Here is yet another approach which combines guards and
where to return a list of roots:
roots a b c = | delta < 0 = error "Cannot solve for complex roots" | delta == 0 = [- b / (2 * a)] | otherwise = [- b / (2 * a) + radix / (2 * a), - b / (2 * a) - radix / (2 * a)] where delta = b * b - 4 * a * c radix = sqrt delta
The first equation uses the builtin error function, which causes
program termination and printing of the string as a diagnostic. Note
that where clauses may occur nested, to arbitrary depth,
allowing Haskell programs to be organized with a nested block
structure. Indentation of inner blocks is compulsory, as layout
information is used by the parser.
Another solution to the sqrt problem is to note that the
sqrt function is actually polymorphic. It
returns a value of the same type as its argument. Hence, if it is
given a real argument, it can return only a real value. Haskell has
library support for complex numbers. Let us try this version of the
function:
import Complex roots a b c = (x1, x2) where x1 = e + sqrt d / (2 * (a :+ 0)) x2 = e - sqrt d / (2 * (a :+ 0)) d = (b * b - 4 * a * c) :+ 0 e = (- b / (2 * a)) :+ 0
This code requires some explanation. First, note that
import works much the same way it did in Python: it makes
a module accessible. In this case, it is a module from the
standard Haskell library. Second, the constructor defined in the
Complex module has the name :+. It is an
infix operator, separating the real part on the left from the
imaginary part on the right. We have to explicitly convert all the
real values in the definition to complex values using this constructor
for Haskell to agree to do arithmetic on the results. Finally, what
is the type of this new version of the function? It is
roots :: Double -> Double -> Double -> (Complex Double, Complex Double)
What does Complex Double mean? Complex is
not a type, but a type constructor. It builds a new type out
of some other type (Double in this case). So you could
make the type Complex Int, for example.
Try the latest version of roots. What does the output
look like for complex roots? What does it look like for real roots?
Can you explain what you see?
Exercise 8: Write a function
addPair :: (Int, Int) -> Int which returns the sum of
the elements of the pair given as its argument.
Exercise 9: Write a function
minAndMax :: Int -> Int -> (Int, Int) which accepts
two integer arguments and returns a tuple containing the minimum and
maximum, respectively, of the arguments.
Exercise 10: Write a function
big3 :: Int ->> Int -> Int -> Int which takes
three numbers as input and returns the largest of the three. Use the
function minAndMax written in Exercise 9 to solve this
problem. (There are easier ways of writing big3, but the
point is to be able to use a function returning a tuple.
Built-in Operators
In addition to the operators below, functions such as
mod or div (integer division) can be placed
in back quotes and used as infix operators. For example, div x
3 can be written as x `div` 3. To get access to
the indicated module, use the import statement in a
program, or enter :also module-name at the Hugs
prompt.
| Operator | Module | Description | Example |
|---|---|---|---|
. |
Function composition | Hugs> negate . abs $ -1 | |
!! |
List dereference | Hugs> [1,2,3,4] !! 1 | |
++ |
List concatenation | Hugs> [1,2,3] ++ [4,5,6] | |
$ |
Right-associative infix application | Hugs> abs -12 | |
&& |
Logical and | Hugs> True && False | |
|| |
Logical or | Hugs> True || False | |
* |
Multiplication | Hugs> 3 * 5 * 7 | |
** |
Exponentiation (power of) | Hugs> 2 ** 10 | |
^ |
** with a nonnegative integer exponent |
Hugs> 2 ^ 10 | |
^^ |
^ with a fractional base |
Hugs> 2 ^^ 10 | |
+ |
Addition | Hugs> 15 + 21 | |
- |
Subtraction | Hugs> 25 - 10 - 4 | |
/ |
Division | Hugs> 2 / 7 | |
== |
Equality | Hugs> 2 + 2 == 4 | |
/= |
Inequality | Hugs> 2 + 2 /= 4 | |
< |
Less than | Hugs> 10 < 20 | |
<= |
Less than or equal | Hugs> 10 <= 20 | |
> |
Greater than | Hugs> 10 > 20 | |
>= |
Greater than or equal | Hugs> 10 >= 20 | |
: |
List insertion | Hugs> 'b' : "at" | |
! |
Array | Array dereference | Array> array (1,3)[(1,1),(2,5),(3,6)] ! 2 |
// |
Array | Array update | Array> (array (0,3)[(0,'W'),(1,'H'),(2,'A'),(3,'T')]) // [(2,'R'),(1,'A')] |
\\ |
List | List difference | List> [1,1,1,2,2,2,3,3,3] \\ [1,2] |
% |
Ratio | Ratio constructor | Ratio> 100 % 200 |
User-Defined Operators
The functions we define are prefix operators because they occur
before their arguments. Infix operators are used between their
arguments (such as 4+3). They can be written before
their arguments (like normal function calls) by enclosing the operator
in parentheses.
Prelude> (+) 4 5
9
We can create user-defined infix operators by combining operator
symbols, namely ! # $ & * + . / ? \ ^ | : - ~.
For example, we can define a new operator &&& as an infix
minimum function.
(&&&) :: Int -> Int-> Int
x &&& y
| x > y = y
| otherwise = x
Exercise 11: Write an infix function
named # which returns the average of its two
Float arguments. Note that / performs
floating point division.
Predefined Types, Constructors, and Classes
Here is a list of the types that all Haskell implementations support
natively (i.e., excluding library-defined types, like
Complex):
()- This is the unit datatype, with only one value, namely
(). It is the equivalent ofNoneTypein Python. Bool- Possible values are
TrueandFalse. Char- Literals are written as in C, namely
'a','b', etc. String- Literals are written as in C, namely
"A string". Int- Fixed-precision integers. The Haskell specification requires that
these be at least 29-bits wide. In practice, both Hugs and GHC
support 32-bit
Ints on 32-bit platforms. Integer- Arbitrary-precision integers.
Float- Single-precision IEEE floating point values (same as a C
float). Double- Double-precision IEEE floating point values (same as a C
double).
In addition, Haskell has several builtin type constructors.
- Lists
- The empty list is written
[]. New elements are added to the front of the list with the:operator; e.g.,1 : [2, 3, 4]. Lists are concatenated with the++operator; e.g.,[1, 2, 3] ++ [4, 5, 6]. Like Python, Haskell supports list comprehensions, although the syntax is slightly different. - Tuples
- These behave much like Python tuples, but surrounding parentheses are required in Haskell (they are optional in Python). All Haskell implementations support tuples up to size at least 15.
- Abstract datatypes
- These are created with the
datakeyword. In fact, the unit type is defined as an abstract datatype. We will say more about these later.
Finally, Haskell supports a number of standard type classes. Think of these as being similar to Java interfaces. They guarantee the existence of certain operators on elements of the class.
Integral- Type class containing the
IntandIntegertypes. RealFloat- Type class containing the
FloatandDoubletypes. RealFrac- Type class containing
RealFloat. The library-definedRatiotype is also a member of this class. Floating- Type class containing
RealFloat. The library-definedComplextype is also a member of this class. Real- Type class containing
IntegralandRealFrac. Fractional- Type class containing
RealFracandFloating. Num- Type class containing
RealandFractional.
We will see some other important type classes later.
Algebraic Types
We have seen the base types, such as Int,
Float, Bool, and Char. We have
seen composite types such as tuples
(t1,t2,…,tn),
list types [t], and function types
(t1->t2->…->tn)
where t, t1, …
tn are themselves types. However, we still
have not seen:
- Enumerated types, like the type of the months January, …, December.
- Union types, like the type whose elements are either a number or a string (useful for street addresses).
- Recursive types, such as trees.
All of these can be modeled as algebraic types. The simplest form of algebraic type is an enumerated type.
data Season = Spring | Summer | Fall | Winter data Weather = Rainy | Hot | Cold data Ordering = LT | EQ| GT -- built into the Ordering Class
A more complicated algebraic type (the product type) allows you to specify types to go with a type constructor, much like Generic Java or C++ templates.
data Student = USU String Int data Address = None | Addr String data Age = Years Int data Shape = Circle Float | Rectangle Float Float
Thus, Student is formed from a String (call
it st) and an Int (call it x) and the
element Student formed from them is USU st
x.
showStudent :: Student -> String showStudent (USU name cred) = name ++ "--" ++ (show cred) Main> showStudent (USU "Jerry" 39) "Jerry--39"
The show function turns cred into a
string. This is necessary, because Haskell knows how to concatenate
strings with ++, but it does not have a concatenation
operator that takes an Int.
Pattern matching is used to define functions by cases:
isRound:: Shape -> Bool isRound (Circle _) = True isRound (Rectangle _ _ ) = False area:: Shape -> Float area (Circle r) = pi * r * r area (Rectangle h w) = h * w
The general form of an algebraic type is:
data Typename =
Constructor1 Type11 … Type1n
Constructor2 Type21 … Type2m
…
Each Constructori is a constructor, which is
followed by zero or more types. We build elements of
Typename by applying the constructor functions to
arguments.
Algebraic types can also be recursive.
data Expr = Lit Int | Add Expr Expr | Sub Expr Expr data BST = Nil | Node Int Tree Tree printBST:: BST -> [Int] printBST Nil = [] printBST (Node x left right) = (printBST left) ++ [x]++ (printBST right)
Here is a sample session showing the use of the binary search tree type.
Main> printBST (Node 5 (Node 3 Nil Nil) Nil) [3,5]
Exercise 12: Using the definition
above, write a function forecast :: Season -> Weather
which accepts the season and predicts the weather forecast. The only
tricky thing is that the system needs to know how to turn instances of
the enumerated type into a string. This is accomplished by the
following:
instance Show Season where show Spring = "Sp" show Summer = "Su" show Fall = "Fa" show Winter = "Wn" instance Show Weather where show Rainy = "Rainy" show Hot = "Hot" show Cold = "Cold"
When the value to be printed is the name of the instance, s simpler
way is to merely add the line deriving(Show) to the data
type definition. This states that the type should be a member of the
indicated type class(es). For example:
data Season = Spring | Summer | Fall | Winter deriving (Ord,Eq,Show)
This declares that the type is a member of type class
Ord, so there is a < operator on the type, and
furthermore Spring < Summer <
Fall < Winter. The type is also a member
of the Eq type class, so the == and
/= operators are defined on elements of the type.
Finally, membership in Show means that elements of the
class can be converted to their string equivalents automatically with
the show function.
Exercise 13: Write the code to insert a value into the binary search tree BST. A constant function definition (which returns a tree) may be helpful in your testing.
aTree = (Node 5 (Node 3 Nil Nil) (Node 10 Nil Nil))
Type Synonyms
For convenience, Haskell provides a way to define type
synonyms — i.e. names for commonly used types. Type
synonyms are created using type declarations, and are like
typedefs in C. Examples include:
type String = [Char] type Person = (Name, Address) type Student2 = (String,Int) type Score = (String,Int) type Name = String
This definition of String is part of the Haskell
Prelude, and in fact the literal syntax "hello" is
shorthand for the list of characters
['h','e','l','l','o']. If you try to use the definitions
above, Hugs gets confused because String is already
defined. It prints an error message like:
ERROR file:.\Misc.hs:5 - Ambiguous type constructor occurrence "String" *** Could refer to: Misc.String Hugs.Prelude.String
To redefine a Prelude type, after the module line, include the line:
import Prelude hiding (String)
If there are several definitions that are to be redefined, separate the names with commas:
import Prelude hiding (String,min,max,add)
What is the difference between Student (defined with
data) and Student2 (defined with
type)? Some people think the Student
version is more readable. Furthermore, it cannot be confused with
other types; Student2 can be confused with
Score. However, Student2 has the advantage
of being in a basic form, so built-in functions can be applied to
elements of that type.
Exercise 14: Using the definitions
above, write a function getName :: Person -> Name
which accepts a person as input and returns that person's name. Note
that an address is not just a string but looks like Addr "100
East 241 South, Richmond". Thus, the call to your function
looks like getName ("Robert Johnson", Addr "241 Highway
89").
Lists
We encountered tuples in the quadratic equation solver. Tuples can have 2, 3, 4, or more elements in them, but the number of elements is fixed. Also, the elements of a tuple can have different types. For example, the first element of a pair may be a name (a string) and the second the age (an number).
A list provides a way to deal with an arbitrary number of elements of
the same type. A list can have no elements at all; this is the empty
list, written []. A list can contain elements of any
type, but all elements must be of the same type. In other words, a
list is a one-dimensional set of elements of the same type (numbers,
strings, Boolean values, etc.). Here are a few examples of lists:
[] | … empty list |
[1, 2] |
… list with elements of type Int |
[True, False] |
… list with elements of type Bool |
[(1, 2), (2, 3)] |
… list of 2-tuples of Int |
[[1, 2], [2, 3, 4]] |
… list of lists of Int |
Strings are lists, too:
"Name" == ['N', 'a', 'm', 'e']
The list constructors, namely [] and :,
give access to the first element of a list and all elements but the
first. Other functions on lists are defined recursively. For
example, the Haskell Prelude defines a !! operator on
lists, which returns then 0-based nth element of a list (so [1,
2, 3] !! 1 evaluates to 2). Here is the definition of
!!:
(!!) :: [a] -> Int -> a
xs !! n | n < 0 = error "Prelude.!!: negative index"
[] !! _ = error "Prelude.!!: index too large"
(x:_) !! 0 = x
(_:xs) !! n = xs !! (n-1)
Other useful Prelude list functions are as follows:
map :: (a -> b) -> [a] -> [b]- Applies a function every element of a list and makes a list of the results
filter :: (a -> Bool) -> [a] -> [a]- Applies a predicate to each element of a list, and makes a list of the elements for which the predicate is true
concat :: [[a]] -> [a]- Takes a list of lists and “flattens” them down into a single list via concatenation
concatMap :: (a -> [b]) -> [a] -> [b]- A combination of
mapandconcat: takes a function that produces lists, maps it over the argument list, and combines all the resulting lists into a single list. head :: [a] -> a- Returns the first element of a nonempty list
tail :: [a] -> [a]- Returns its argument list minus its head element
last :: [a] -> a- Returns the last element of a finite list
init :: [a] -> [a]- Returns its argument list minus its last element
null :: [a] -> Bool- A predicate on lists that is
Trueif and only if its argument list is empty length :: [a] -> Int- Returns the number of elements in a finite list
foldl :: (a -> b -> a) -> a -> [b] -> a- Takes a binary operator, a starting value (usually the
“zero” of the operator), and a list. The operator is
applied to the starting value and the first element of the list,
then the result of that and the second element of the list, then the
result of that and the third element of the list, etc. For example,
foldl max 0 [5, 5498, 4, -30] == 5498. foldl1 :: (a -> a -> a) -> [a] -> a- The same as
foldl, but does not take a starting value. This version can only be applied to nonempty lists. For a list of length one, its value is the single list element; otherwise, it applies the operator to the first two elements of the list, etc. scanl :: (a -> b -> a) -> a -> [b] -> [a]- Like
foldl, but produces a list of all of the intermediate results. Therefore, the last element of the list produced byscanlis the value produced byfoldlon the same arguments. For example,scanl max 0 [5, 5498, 4, -30] == [0, 5, 5498, 5498, 5498]. scanl1 :: (a -> a -> a) -> [a] -> [a]- Like
scanl, but does not take a starting value, and must be applied to nonempty lists foldr :: (a -> b -> b) -> b -> [a] -> b- Like
foldl, but starts from the end of the list and works back toward the beginning. For example,foldr (-) 0 [20, 10, 5] == 15, because the computation is (20 - (10 - (5 - 0))). On the other hand,foldl (-) 0 [20, 10, 5] == -35, because the computation is ((0 - 20) - 10) - 5. foldr1 :: (a -> a -> a) -> [a] -> a- Like
foldl1, but starts from the end of the list and works back toward the beginning. scanr :: (a -> b -> b) -> b -> [a] -> [b]- Like
scanl, but starts from the end of the list and works back toward the beginning. scanr1 :: (a -> a -> a) -> [a] -> [a]- Like
scanl1, but starts from the end of the list and works back toward the beginning. iterate :: (a -> a) -> a -> [a]- Given a function
fand a starting elementx, returns an infinite list[x, f x, f (f x), …]. For example,iterate (\x -> x + 1) 0 == [0, 1, 2, 3, 4, …]. Warning: do not try to evaluate that expression at the interpreter prompt! repeat :: a -> [a]- Returns an infinite list consisting of the same element over and over and over again.
replicate :: Int -> a -> [a]- Returns a finite list of specified length consisting of the same
element over and over again. For example,
replicate 5 True == [True, True, True, True, True] cycle :: [a] -> [a]- Turns a finite nonempty list into an infinite list by repeating
the original list over and over again. For example,
cycle ['a', 'b', 'c'] == ['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c', …]. take :: Int -> [a] -> [a]- Returns the first n elements of a list (or the entire
list if n is bigger than the length of the list). For
example,
take 3 [10, 20, 30, 40, 50, 60, 70] == [10, 20, 30]. drop :: Int -> [a] -> [a]- Returns a list with the first n elements removed (or
the empty list if n is bigger than the length of the
list). For example,
drop 3 [10, 20, 30, 40, 50, 60, 70] == [40, 50, 60, 70]. splitAt :: Int -> [a] -> ([a], [a])- A combination of
takeanddrop, this function returns a 2-tuple containing the original list split into two at the specified index. For example,splitAt 3 [10, 20, 30, 40, 50, 60, 70] == ([10,20,30], [40,50,60,70]). takeWhile :: (a -> Bool) -> [a] -> [a]- Returns the longest prefix of a list where each element satisfies
a predicate. For example,
takeWhile (\x -> x < 30) [10, 15, 20, 30, 20, 15, 10] == [10, 15, 20]. dropWhile :: (a -> Bool) -> [a] -> [a]- Removes the longest prefix of a list where each element satisfies
a predicate. For example,
dropWhile (\x -> x < 30) [10, 15, 20, 30, 20, 15, 10] == [30, 20, 15, 10]. span :: (a -> Bool) -> [a] -> ([a], [a])- Like
splitAt, but usingtakeWhileanddropWhile. For example,span (\x -> x < 30) [10, 15, 20, 30, 20, 15, 10] == ([10, 15, 20], [30, 20, 15, 10]). break :: (a -> Bool) -> [a] -> ([a],[a])- Like
span, but reverses the sense of the predicate. For example,break (\x -> x >= 30) [10, 15, 20, 30, 20, 15, 10] == ([10, 15, 20], [30, 20, 15, 10]). reverse :: [a] -> [a]- Returns its argument list (which had better be finite) in reverse
order. For example,
reverse [1, 2, 3] == [3, 2, 1]. any :: (a -> Bool) -> [a] -> Bool- Given a predicate and a list, returns true if the predicate holds for some member of the list.
all :: (a -> Bool) -> [a] -> Bool- Given a predicate and a list, returns true if the predicate holds for every member of the list.
elem :: (Eq a) => a -> [a] -> Bool- Given a list of elements that can be tested for equality,
determines whether a given element is a member of the list. This is
usually written using Haskell's infix notation: the
function name is surrounded with backticks. For example,
5 `elem` [1, 2, 3, 4, 5] == True. notElem :: (Eq a) => a -> [a] -> Bool- Determines whether an element is not a member of some list.
maximum :: (Ord a) => [a] -> a- Given a nonempty list of elements of some ordered type, return the maximum element in the list.
minimum :: (Ord a) => [a] -> a- Given a nonempty list of elements of some ordered type, return the minimum element in the list.
zip :: [a] -> [b] -> [(a, b)]- Pair corresponding members of two lists together to make a single list of 2-tuples. If one list is longer than the other, then the extra elements are discarded.
unzip :: [(a,b)] -> ([a], [b])- From a list of pairs, produce a pair of lists.
Recursion, or “Who stole loops and counters?”
Recursive functions are often specified with patterns. That is, the function is written with more than one equation, and the Haskell runtime system does pattern-matching on the parameters to figure out which equation is applicable. For example, here is the factorial function written in Haskell.
fact 0 = 1 -- base case
fact n = n * fact (n - 1) -- induction step
When this function is called, Haskell checks whether the parameter is 0. If so, it matches the first equation and evaluates to 1. Otherwise, it matches the second equation. Functions can be written with any number of equations.
Recursive functions that operate on lists are quite common. There,
the base case is the empty list, and the induction step recursively
operates on a list one element shorter than its argument. The
!! function for finding the nth element of a list is an
example of such a recursive function.
Last modified: Thu Nov 9 21:16:17 MST 2006 by Jerry James