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.

Built-in Haskell operators
OperatorModuleDescription Example
.   Function composition Hugs> negate . abs $ -1
-1
!!   List dereference Hugs> [1,2,3,4] !! 1
2
++   List concatenation Hugs> [1,2,3] ++ [4,5,6]
[1,2,3,4,5,6]
Hugs> "String1" ++ "String2"
"String1String2"
$   Right-associative infix application Hugs> abs -12
ERROR - Cannot infer instance
*** Instance : Num (a -> a)
*** Expression : abs - 12
Hugs> abs $ -12
12
&&   Logical and Hugs> True && False
False
||   Logical or Hugs> True || False
True
*   Multiplication Hugs> 3 * 5 * 7
105
**   Exponentiation (power of) Hugs> 2 ** 10
1024.0
^   ** with a nonnegative integer exponent Hugs> 2 ^ 10
1024
^^   ^ with a fractional base Hugs> 2 ^^ 10
1024.0
+   Addition Hugs> 15 + 21
36
-   Subtraction Hugs> 25 - 10 - 4
11
/   Division Hugs> 2 / 7
0.285714285714286
Hugs> :also Ratio
Ratio> (5 % 7) / (6 % 7)
5 % 6
==   Equality Hugs> 2 + 2 == 4
True
/=   Inequality Hugs> 2 + 2 /= 4
False
<   Less than Hugs> 10 < 20
True
<=   Less than or equal Hugs> 10 <= 20
True
>   Greater than Hugs> 10 > 20
False
>=   Greater than or equal Hugs> 10 >= 20
False
:   List insertion Hugs> 'b' : "at"
"bat"
Hugs> 1 : [2, 3, 4, 5]
[1,2,3,4,5]
! Array Array dereference Array> array (1,3)[(1,1),(2,5),(3,6)] ! 2
5
// Array Array update Array> (array (0,3)[(0,'W'),(1,'H'),(2,'A'),(3,'T')]) // [(2,'R'),(1,'A')]
array (0,3) [(0,'W'),(1,'A'),(2,'R'),(3,'T')]
\\ List List difference List> [1,1,1,2,2,2,3,3,3] \\ [1,2]
[1,1,2,2,3,3,3]
% Ratio Ratio constructor Ratio> 100 % 200
1 % 2

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 of NoneType in Python.
Bool
Possible values are True and False.
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 data keyword. 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 Int and Integer types.
RealFloat
Type class containing the Float and Double types.
RealFrac
Type class containing RealFloat. The library-defined Ratio type is also a member of this class.
Floating
Type class containing RealFloat. The library-defined Complex type is also a member of this class.
Real
Type class containing Integral and RealFrac.
Fractional
Type class containing RealFrac and Floating.
Num
Type class containing Real and Fractional.

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:

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 map and concat: 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 True if 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 by scanl is the value produced by foldl on 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 f and a starting element x, 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 take and drop, 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 using takeWhile and dropWhile. 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