text:
Yet Another Haskell Tutorial/Getting started

There are three well known Haskell systems: Hugs, GHC and NHC. Hugs is exclusively an interpreter, meaning that you cannot compile stand-alone programs with it, but can test and debug programs in an interactive environment. GHC is both an interpreter (like Hugs) and a compiler which will produce stand-alone programs. NHC is exclusively a compiler. Which you use is entirely up to you. I've tried to make a list of some of the differences in the following list but of course this is far from exhaustive:

 * Hugs - very fast to load files, slow to run them; implements almost all of Haskell 98 (the standard) and most extensions; built-in support for module browsing; cannot create stand-alones; written in C; works on almost every platform; built-in graphics library.
 * GHC - interactive environment is slower than Hugs to load, but allows function definitions in the environment (in Hugs you have to put them in a file); implements all of Haskell 98 and extensions; good support for interfacing with other languages; in a sense the "de facto" standard. It also allows compiled objects to be loaded and tested.
 * NHC - less used and no interactive environment, but produces smaller and often faster executables than does GHC; supports Haskell98 and some extensions.

I, personally, have all of them installed and use them for different purposes. I tend to use GHC to compile (primarily because I'm most familiar with it) and the Hugs interactive environment, since it is much faster. As such, this is what I would suggest. However, that is a fair amount to download and install, so if you had to go with just one, I'd get GHC, since it contains both a compiler and interactive environment.

Following is a description of how to download and install each of these as of the time this tutorial was written. It may have changed -- see the Haskell website for up-to-date information.

Hugs
Hugs supports almost all of the Haskell 98 standard (it lacks some of the libraries), as well as a number of advanced/experimental extensions, including: multi-parameter type classes, extensible records, rank-2 polymorphism, existentials, scoped type variables, and restricted type synonyms.

Where to get it
The official Hugs web page is at.

If you go there, there is a link titled "downloading" which will send you to the download page. From that page, you can download the appropriate version of Hugs for your computer.

Installation procedures
Once you've downloaded Hugs, installation differs depending on your platform, however, installation for Hugs is more or less identical to installation for any program on your platform.

simply choose "Run This Program" and the installation will begin automatically. From there, just follow the on-screen instructions.
 * For Windows when you click on the "msi" file to download,
 * For RPMs use whatever RPM installation program you know best.
 * For source first gunzip the file, then untar it. Presumably if you're using a system which isn't otherwise supported, you know enough about your system to be able to run configure scripts and make things by hand.

How to run it
On Unix machines, the Hugs interpreter is usually started with a command line of the form: hugs [option | file] ...

On Windows, Hugs may be started by selecting it from the start menu or by double clicking on a file with the .hs or .lhs extension. (This manual assumes that Hugs has already been successfully installed on your system.)

Hugs uses options to set system parameters. These options are distinguished by a leading + or - and are used to customize the behavior of the interpreter. When Hugs starts, the interpreter performs the following tasks:

 * Options in the environment are processed. The variable HUGSFLAGS holds these options. On Windows 95/NT, the registry is also queried for Hugs option settings.
 * Command line options are processed.
 * Internal data structures are initialized. In particular, the heap is initialized, and its size is fixed at this point; if you want to run the interpreter with a heap size other than the default, then this must be specified using options on the command line, in the environment or in the registry.
 * The prelude file is loaded. The interpreter will look for the prelude file on the path specified by the -P option. If the prelude, located in the file Prelude.hs, cannot be found in one of the path directories or in the current directory, then Hugs will terminate; Hugs will not run without the prelude file.
 * Program files specified on the command line are loaded. The effect of a command hugs f1 ... fn is the same as starting up Hugs with the hugs command and then typing :load f1 ... fn. In particular, the interpreter will not terminate if a problem occurs while it is trying to load one of the specified files, but it will abort the attempted load command.

The environment variables and command line options used by Hugs are described in the following sections.

Program options
To list all of the options would take too much space. The most important option at this point is "+98" or "-98". When you start hugs with "+98" it is in Haskell 98 mode, which turns off all extensions. When you start in "-98", you are in Hugs mode and all extensions are turned on. If you've downloaded someone else's code and you're having trouble loading it, first make sure you have the "98" flag set properly.

Further information on the Hugs options is in the manual: http://cvs.haskell.org/Hugs/pages/hugsman/started.html

How to get help
To get Hugs specific help, go to the Hugs web page. To get general Haskell help, go to the Haskell web page.

Glasgow Haskell Compiler
The Glasgow Haskell Compiler (GHC) is a robust, fully-featured, optimizing compiler and interactive environment for Haskell 98; GHC compiles Haskell to either native code or C. It implements numerous experimental language extensions to Haskell 98; for example: concurrency, a foreign language interface, multi-parameter type classes, scoped type variables, existential and universal quantification, unboxed types, exceptions, weak pointers, and so on. GHC comes with a generational garbage collector, and a space and time profiler.

Where to get it
Go to the official GHC web page GHC to download the latest release. The current version as of the writing of this tutorial is 5.04.2 and can be downloaded off of the GHC download page (follow the "Download" link). From that page, you can download the appropriate version of GHC for your computer.

Installation procedures
Once you've downloaded GHC, installation differs depending on your platform; however, installation for GHC is more or less identical to installation for any program on your platform.

 * For Windows when you click on the "msi" file to download, simply choose "Run This Program" and the installation will begin automatically. From there, just follow the on-screen instructions.

 * For RPMs use whatever RPM installation program you know best.

 * For source first gunzip the file, then untar it. Presumably if you're using a system which isn't otherwise supported, you know enough about your system to be able to run configure scripts and make things by hand.

For a more detailed description of the installation procedure, look at the GHC users manual under "Installing GHC".

How to run the compiler
Running the compiler is fairly easy. Assuming that you have a program written with a  function in a file called Main.hs, you can compile it simply by writing:

The "--make" option tells GHC that this is a program and not just a library and you want to build it and all modules it depends on. "Main.hs" stipulates the name of the file to compile; and the "-o main" means that you want to put the output in a file called "main".

You can then run the program by simply typing "./main" at the prompt.

How to run the interpreter
GHCi is invoked with the command "ghci" or "ghc --interactive". One or more modules or filenames can also be specified on the command line; this instructs GHCi to load the specified modules or filenames (and all the modules they depend on), just as if you had said :load modules at the GHCi prompt.

To get help within the interpreter, type ":?" at the prompt. To quit, type ":q". To interrupt a running computation, press control-c.

Program options
To list all of the options would take too much space. The most important option at this point is "-fglasgow-exts". When you start GHCi without "-fglasgow-exts" it is in Haskell 98 mode, which turns off all extensions. When you start with "-fglasgow-exts", all extensions are turned on. If you've downloaded someone else's code and you're having trouble loading it, first make sure you have this flag set properly.

Further information on the GHC and GHCi options are in the manual off of the GHC web page.

How to get help
To get GHC(i) specific help, go to the GHC web page. To get general Haskell help, go to the Haskell web page.

NHC
About NHC...

Editors
With a good text editor, programming is fun. Of course, you can get along with a simplistic editor capable of just cut-n-paste, but a good editor is capable of doing most of the chores for you, letting you concentrate on what you are writing. With respect to programming in Haskell, a good text editor should have as many as possible of the following features:

 * Syntax highlighting for source files
 * Indentation of source files
 * Interaction with Haskell interpreter (be it Hugs or GHCi)
 * Computer-aided code navigation
 * Code completion

At the time of writing, several options were available: Emacs/XEmacs support Haskell via haskell-mode and accompanying Elisp code (available from ), and ... . %todo: what else?

What's else available?...

(X)Emacs seem to do the best job, having all the features listed above. Indentation is aware about Haskell's 2-dimensional layout rules (see the section on Layout, very smart and have to be seen in action to be believed. You can quickly jump to the definition of chosen function with the help of "Definitions" menu, and name of the currently edited function is always displayed in the modeline. %todo: more?


text:
Yet Another Haskell Tutorial/Language basics

In this chapter we present the basic concepts of Haskell. In addition to familiarizing you with the interactive environments and showing you how to compile a basic program, we introduce the basic syntax of Haskell, which will probably be quite alien if you are used to languages like C and Java.

However, before we talk about specifics of the language, we need to establish some general properties of Haskell. Most importantly, Haskell is a lazy language, which means that no computation takes place unless it is forced to take place when the result of that computation is used.

This means, for instance, that you can define infinitely large data structures, provided that you never use the entire structure. For instance, using imperative-esque pseudo-code, we could create an infinite linked-list containing the number $$1$$ in each position by doing something like:

List makeList { List current = new List; current.value = 1; current.next = makeList; return current; } By looking at this code, we can see what it's trying to do: it creates a new list, sets its value to $$1$$ and then recursively calls itself to make the rest of the list. Of course, if you actually wrote this code and called it, the program would never terminate, because  would keep calling itself ad infinitum.

This is because we assume this imperative-esque language is strict, the opposite of lazy. Strict languages are often referred to as "call by value," while lazy languages are referred to as "call by name." In the above pseudo-code, when we "run" makeList on the fifth line, we attempt to get a value out of it. This leads to an infinite loop.

The equivalent code in Haskell is:

makeList = 1 : makeList This program reads: we're defining something called (this is what goes on the left-hand side of the equals sign). On the right-hand side, we give the definition of. In Haskell, the colon operator is used to create lists (we'll talk more about this soon). This right-hand side says that the value of is the element   stuck on to the beginning of the value of.

However, since Haskell is lazy (or "call by name"), we do not actually attempt to evaluate what  is at this point: we simply remember that if ever in the future we need the second element of, we need to just look at.

Now, if you attempt to write  to a file, print it to the screen, or calculate the sum of its elements, the operation won't terminate because it would have to evaluate an infinitely long list. However, if you simply use a finite portion of the list (say the first $$10$$ elements), the fact that the list is infinitely long doesn't matter. If you only use the first $$10$$ elements, only the first $$10$$ elements are ever calculated. This is laziness.

Second, Haskell is case-sensitive. Many languages are, but Haskell actually uses case to give meaning. Haskell distinguishes between values (for instance, numbers: $$1,2,3,...$$); strings: "abc", "hello", ...; characters: 'a', 'b', ' ', ...; even functions (for instance, the function that squares a value, or the square-root function); and types (the categories to which values belong).

By itself, this is not unusual. Most languages have some system of types. What is unusual is that Haskell requires that the names given to functions and values begin with a lower-case letter and that the names given to types begin with an upper-case letter. The moral is: if your otherwise correct program won't compile, be sure you haven't named your function, or something else beginning with a capital letter.

Being a functional language, Haskell eschews side effects. A side effect is essentially something that happens in the course of executing a function that is not related to the output produced by that function.

For instance, in a language like C or Java, you are able to modify "global" variables from within a function. This is a side effect because the modification of this global variable is not related to the output produced by the function. Furthermore, modifying the state of the real world is considered a side effect: printing something to the screen, reading a file, etc., are all side effecting operations.

Functions that do not have side effects are called pure. An easy test for whether or not a function is pure is to ask yourself a simple question: "Does this function's result depend only on the arguments it receives, and is returning a result the only thing it does?"

All of this means that if you're used to writing code in an imperative language (like C or Java), you're going to have to start thinking differently. Most importantly, if you have a value, you must not think of  as a register, a memory location or anything else of that nature. is simply a name, just as "Hal" is my name. You cannot arbitrarily decide to store a different person in my name any more than you can arbitrarily decide to store a different value in. This means that code that might look like the following C code is invalid (and has no counterpart) in Haskell:

int x = 5; x = x + 1; A call like x = x + 1 is called destructive update because we are destroying whatever was in x before and replacing it with a new value. Destructive update does not exist in Haskell.

By not allowing destructive updates (or any other such side effecting operations), Haskell code is very easy to comprehend. That is, when we define a function, and call that function with a particular argument  in the beginning of a program, and then, at the end of the program, again call with the same argument, we know we will get out the same result. This is because we know that  cannot have changed and because we know that  only depends on   (for instance, it didn't increment a global counter). This property is called referential transparency and basically states that if two functions  and   produce the same values for the same arguments, then we may replace  with (and vice-versa).

Arithmetic
Let's begin our foray into Haskell with simple arithmetic. Start up your favorite interactive shell (Hugs or GHCi; see the chapter Getting started for installation instructions). The shell will output to the screen a few lines talking about itself and what it's doing and then should finish with the cursor on a line reading:

From here, you can begin to evaluate expressions. An expression is basically something that has a value. For instance, the number $$5$$ is an expression (its value is $$5$$). Values can be built up from other values; for instance, $$5+6$$ is an expression (its value is $$11$$). In fact, most simple arithmetic operations are supported by Haskell, including plus, minus , times , divided-by , exponentiation and square-root. You can experiment with these by asking the interactive shell to evaluate expressions and to give you their value. In this way, a Haskell shell can be used as a powerful calculator. Try some of the following:

We can see that, in addition to the standard arithmetic operations, Haskell also allows grouping by parentheses, hence the difference between the values of 5*4+3 and 5*(4+3). The reason for this is that the "understood" grouping of the first expression is (5*4)+3, due to operator precedence.

Also note that parentheses aren't required around function arguments. For instance, we simply wrote, not  , as would be required in most other languages. You could write it with the parentheses, but in Haskell, since function application is so common, parentheses aren't required.

Now try entering 2^5000. Does it work?

Pairs, Triples and More
In addition to single values, we should also address multiple values. For instance, we may want to refer to a position by its $$x$$/$$y$$ coordinate, which would be a pair of integers. To make a pair of integers is simple: you enclose the pair in parenthesis and separate them with a comma. Try the following:

Here, we have a pair of integers, $$5$$ and $$3$$. In Haskell, the first element of a pair need not have the same type as the second element: that is, pairs are allowed to be heterogeneous. For instance, you can have a pair of an integer with a string. This contrasts with lists, which must be made up of elements of all the same type (we will discuss lists further in the section on Lists).

There are two predefined functions that allow you to extract the first and second elements of a pair. They are, respectively, and. You can see how they work below:

In addition to pairs, you can define triples, quadruples etc. To define a triple and a quadruple, respectively, we write:

And so on. In general, pairs, triples, and so on are called tuples and can store fixed amounts of heterogeneous data.

Lists
The primary limitation of tuples is that they hold only a fixed number of elements: pairs hold two, triples hold three, and so on. A data structure that can hold an arbitrary number of elements is a list. Lists are assembled in a very similar fashion to tuples, except that they use square brackets instead of parentheses. We can define a list like:

Lists don't need to have any elements. The empty list is simply.

Unlike tuples, we can very easily add an element on to the beginning of the list using the colon operator. The colon is called the "cons" operator; the process of adding an element is called "consing." The etymology of this is that we are constructing a new list from an element and an old list. We can see the cons operator in action in the following examples:

We can actually build any list by using the cons operator (the colon) and the empty list:

In fact, the  syntax is "syntactic sugar" for the expression using the explicit cons operators and empty list. If we write something using the notation, the compiler simply translates it to the expression using  and.

One further difference between lists and tuples is that, while tuples are heterogeneous, lists must be homogeneous. This means that you cannot have a list that holds both integers and strings. If you try to, a type error will be reported.

Of course, lists don't have to just contain integers or strings; they can also contain tuples or even other lists. Tuples, similarly, can contain lists and other tuples. Try some of the following:

There are two basic list functions: and. The  function returns the first element of a (non-empty) list, and the  function returns all but the first element of a (non-empty) list.

To get the length of a list, you use the  function:

Strings
In Haskell, a  is simply a list of  s.  So, we can create the string "Hello" as:

Lists (and, of course, strings) can be concatenated using the  operator:

Additionally, non-string values can be converted to strings using the function, and strings can be converted to non-string values using the  function. Of course, if you try to read a value that's malformed, an error will be reported (note that this is a run-time error, not a compile-time error):

In the above, the exact error message is implementation dependent. However, the interpreter has inferred that you're trying to add three to something. This means that when we execute, we expect to be returned a number. However,  cannot be parsed as a number, so an error is reported.

Simple List Functions
Much of the computation in Haskell programs is done by processing lists. There are three primary list-processing functions: , and  (also  ).

The  function takes as arguments a list of values and a function that should be applied to each of the values. It returns the result of this application. For instance, there is a built-in function  that takes as input a  and produces a   that is the upper-case version of the original argument. So, to convert an entire string (which is simply a list of characters) to upper case, we can map the function across the entire list:

When you map across a list, the length of the list never changes -- only the individual values in the list change.

To remove elements from the list, you can use the function. This function allows you to remove certain elements from a list depending on their value, but not on their context. For instance, the function  tells you whether a given character is lower case. We can filter out all non-lowercase characters using this:

The function  takes a little more getting used to. takes three arguments: a function, an initial value and a list. The best way to think about  is that it replaces occurrences of the list cons operator with the function parameter and replaces the empty list constructor with the initial value. Thus, if we have a list:

3 : 8 : 12 : 5 : [] and we apply  to it, we get:

3 + 8 + 12 + 5 + 0 which sums the list. We can test this:

We can perform the same sort of operation to calculate the product of all the elements on a list:

We said earlier that folding is like replacing with a particular function and  with an initial element. This raises a question as to what happens when the function isn't associative (a function ($$\cdot$$) is associative if $$a \cdot (b \cdot c) = (a \cdot b) \cdot c$$). When we write $$4 \cdot 8 \cdot 5 \cdot 1$$, we need to specify where to put the parentheses. Namely, do we mean $$((4 \cdot 8) \cdot 5) \cdot 1$$ or $$4 \cdot (8 \cdot (5 \cdot 1))$$? assumes the function is right-associative (i.e., the correct bracketing is the latter). Thus, when we use it on a non-associative function (like minus), we can see the effect:

The exact derivation of this looks something like:

foldr (-) 1 [4,8,5] ==> 4 - (foldr (-) 1 [8,5]) ==> 4 - (8 - foldr (-) 1 [5]) ==> 4 - (8 - (5 - foldr (-) 1 [])) ==> 4 - (8 - (5 - 1)) ==>  4 - (8 - 4) ==>  4 - 4 ==>  0 The   function goes the other way and effectively produces the opposite bracketing. looks the same when applied, so we could have done summing just as well with :

However, we get different results when using the non-associative function minus:

This is because  uses the opposite bracketing. The way it accomplishes this is essentially by going all the way down the list, taking the last element and combining it with the initial value via the provided function. It then takes the second-to-last element in the list and combines it to this new value. It does so until there is no more list left.

The derivation here proceeds in the opposite fashion:

foldl (-) 1 [4,8,5] ==> foldl (-) (1 - 4) [8,5] ==> foldl (-) ((1 - 4) - 8) [5] ==> foldl (-) (((1 - 4) - 8) - 5) [] ==> ((1 - 4) - 8) - 5 ==>  ((-3) - 8) - 5 ==>  (-11) - 5 ==>  -16 Note that once the   goes away, the parenthesization is exactly the opposite of the.

If this discussion of the folding functions is still somewhat unclear, that's okay. We'll discuss them further in the section on Lists.

Source Code Files
As programmers, we don't want to simply evaluate small expressions like these -- we want to sit down, write code in our editor of choice, save it and then use it.

We already saw in the sections Ghc and Nhc how to write a Hello World program and how to compile it. Here, we show how to use functions defined in a source-code file in the interactive environment. To do this, create a file called <tt>Test.hs</tt> and enter the following code:

module Test where

x = 5 y = (6, "Hello") z = x * fst y This is a very simple "program" written in Haskell. It defines a module called "Test" (in general module names should match file names; see the section on Modules for more on this). In this module, there are three definitions: x, y and z. Once you've written and saved this file, in the directory in which you saved it, load this in your favorite interpreter, by executing either of the following:

This will start Hugs or GHCi, respectively, and load the file. Alternatively, if you already have one of them loaded, you can use the ":load" command (or just ":l") to load a module, as:

Between the first and last line, the interpreter will print various data to explain what it is doing. If any errors appear, you probably mistyped something in the file; double check and then try again.

You'll notice that where it used to say "Prelude" it now says "Test." That means that Test is the current module. The Prelude module (usually simply referred to as "the Prelude") is always loaded and contains the standard definitions (for instance, the operator for lists, or  or,  ,   and so on).

Now that we've loaded Test, we can use things that were defined in it. For example:

Perfect, just as we expected!

One final issue regarding how to compile programs to stand-alone executables remains. In order for a program to be an executable, it must have the module name "Main" and must contain a function called. So, if you go in to Test.hs and rename it to "Main" (change the line that reads  to  ), we simply need to add a main function. Try this:

main = putStrLn "Hello World" Now, save the file, and compile it (refer back to the section on Getting started for information on how to do this for your compiler). For example, in GHC, you would say:

This will create a file called "test" (or on Windows, "test.exe") that you can then run.

Functions
Now that we've seen how to write code in a file, we can start writing functions. As you might have expected, functions are central to Haskell, as it is a functional language. This means that the evaluation of a program is simply the evaluation of a function.

We can write a simple function to square a number and enter it into our <tt>Test.hs</tt> file. We might define this as follows:

square x = x * x In this function definition, we say that we're defining a function that takes one argument (aka parameter), which we call . We then say that the value of   is equal to.

Haskell also supports standard conditional expressions. For instance, we could define a function that returns $$-1$$ if its argument is less than $$0$$; $$0$$ if its argument is $$0$$; and $$1$$ if its argument is greater than $$0$$ (this is called the signum function):

signum x = if x < 0 then -1 else if x > 0 then 1 else 0 You can experiment with this as:

Note that the parenthesis around "-1" in the last example are required; if missing, the system will think you are trying to subtract the value "1" from the value "signum," which is illtyped.

The if/then/else construct in Haskell is very similar to that of most other programming languages; however, you must have both a <tt>then</tt> and an <tt>else</tt> clause. It evaluates the condition (in this case $$x < 0$$ and, if this evaluates to, it evaluates the <tt>then</tt> clause; if the condition evaluated to  , it evaluates the <tt>else</tt> clause).

You can test this program by editing the file and loading it back into your interpreter. If <tt>Test</tt> is already the current module, instead of typing <tt>:l Test.hs</tt> again, you can simply type <tt>:reload</tt> or just <tt>:r</tt> to reload the current file. This is usually much faster.

Haskell, like many other languages, also supports <tt>case</tt> constructions. These are used when there are multiple values that you want to check against (case expressions are actually quite a bit more powerful than this -- see the section on Pattern matching for all of the details).

Suppose we wanted to define a function that had a value of $$1$$ if its argument were $$0$$; a value of $$5$$ if its argument were $$1$$; a value of $$2$$ if its argument were $$2$$; and a value of $$-1$$ in all other instances. Writing this function using <tt>if</tt> statements would be long and very unreadable; so we write it using a <tt>case</tt> statement as follows (we call this function ):

f x = case x of     0 -> 1 1 -> 5     2 -> 2      _ -> -1 In this program, we're defining   to take an argument   and then inspect the value of. If it matches $$0$$, the value of is $$1$$. If it matches $$1$$, the value of  is $$5$$. If it maches $$2$$, then the value of  is $$2$$; and if it hasn't matched anything by that point, the value of  is $$-1$$ (the underscore can be thought of as a "wildcard" -- it will match anything).

The indentation here is important. Haskell uses a system called "layout" to structure its code (the programming language Python uses a similar system). The layout system allows you to write code without the explicit semicolons and braces that other languages like C and Java require.

The general rule for layout is that an open-brace is inserted after the keywords <tt>where</tt>, <tt>let</tt>, <tt>do</tt> and <tt>of</tt>, and the column position at which the next command appears is remembered. From then on, a semicolon is inserted before every new line that is indented the same amount. If a following line is indented less, a close-brace is inserted. This may sound complicated, but if you follow the general rule of indenting after each of those keywords, you'll never have to remember it (see the section on Layout for a more complete discussion of layout).

Some people prefer not to use layout and write the braces and semicolons explicitly. This is perfectly acceptable. In this style, the above function might look like:

f x = case x of       { 0 -> 1 ; 1 -> 5 ; 2 -> 2 ; _ -> -1 } Of course, if you write the braces and semicolons explicitly, you're free to structure the code as you wish. The following is also equally valid:

f x = case x of { 0 -> 1 ; 1 -> 5 ; 2 -> 2  ; _ -> -1 } However, structuring your code like this only serves to make it unreadable (in this case).

Functions can also be defined piece-wise, meaning that you can write one version of your function for certain parameters and then another version for other parameters. For instance, the above function could also be written as:

f 0 = 1 f 1 = 5 f 2 = 2 f _ = -1 Here, the order is important. If we had put the last line first, it would have matched every argument, and  would return  , regardless of its argument (most compilers will warn you about this, though, saying something about overlapping patterns). If we had not included this last line,  would produce an error if anything other than 0, 1 or 2 were applied to it (most compilers will warn you about this, too, saying something about incomplete patterns). This style of piece-wise definition is very popular and will be used quite frequently throughout this tutorial. These two definitions of are actually equivalent -- this piece-wise version is translated into the case expression.

More complicated functions can be built from simpler functions using function composition. Function composition is simply taking the result of the application of one function and using that as an argument for another. We've already seen this way back in arithmetic (the section on Arithmetic), when we wrote. In this, we were evaluating $$5*4$$ and then applying $$+3$$ to the result. We can do the same thing with our  and functions:

The result of each of these function applications is fairly straightforward. The parentheses around the inner function are necessary; otherwise, in the first line, the interpreter would think that you were trying to get the value of " ," which has no meaning. Function application like this is fairly standard in most programming languages. There is another, more mathematically oriented, way to express function composition, using the (just a single period) function. This function is supposed to look like the ($$\circ$$) operator in mathematics.

The function (called the function composition function), takes two functions and makes them in to one. For instance, if we write, this means that it creates a new function that takes an argument, applies  to that argument and then applies  to the result. Conversely, means that it creates a new function that takes an argument, applies to that argument and then applies  to the result. We can see this by testing it as before:

Here, we must enclose the function composition in parentheses; otherwise, the Haskell compiler will think we're trying to compose with the value  in the first line, which makes no sense since   isn't even a function.

It would probably be wise to take a little time-out to look at some of the functions that are defined in the Prelude. Undoubtedly, at some point, you will accidentally rewrite some already-existing function (I've done it more times than I can count), but if we can keep this to a minimum, that would save a lot of time. Here are some simple functions, some of which we've already seen:

Here, we show example usages of each of these functions:

We can see that applying  to an empty list gives an error (the exact error message depends on whether you're using GHCi or Hugs -- the shown error message is from Hugs).

Let Bindings
Often we wish to provide local declarations for use in our functions. For instance, the following equation is used to find the roots (zeros) of a polynomial of the form $$ax^2+bx+c=0$$: $$x = (-b \pm \sqrt{b^2-4ac}) / (2a)$$. We could write the following function to compute the two values of $$x$$:

roots a b c = ((-b + sqrt(b*b - 4*a*c)) / (2*a),    (-b - sqrt(b*b - 4*a*c)) / (2*a))

Unfortunately, we duplicate expressions here. To remedy this problem, Haskell allows for local bindings. That is, we can create values inside of a function that only that function can see. For instance, we could create a local binding for the expression , calling it  for discriminant, and then use that in both places where   occurred. We can do this using a <tt>let</tt>/<tt>in</tt> declaration:

roots a b c = let discr = sqrt (b*b - 4*a*c) in ((-b + discr) / (2*a),         (-b - discr) / (2*a)) In fact, you can provide multiple declarations inside a let. Just make sure they're indented the same amount, or you will have layout problems:

roots a b c = let discr = sqrt (b*b - 4*a*c) twice_a = 2*a in ((-b + discr) / twice_a,         (-b - discr) / twice_a)

Infix
Infix functions are ones that are composed of symbols, rather than letters. For instance,,  ,   are all infix functions. You can use them in non-infix mode by enclosing them in parentheses. Hence, the two following expressions are the same:

Similarly, non-infix functions (like ) can be made infix by enclosing them in backquotes (the ticks on the tilde key on American keyboards):

Comments
There are two types of comments in Haskell: line comments and block comments. Line comments begin with the token  and extend until the end of the line. Block comments begin with  and extend to a corresponding. Block comments can be nested.

Comments are used to explain your program in English and are completely ignored by compilers and interpreters. For example:

module Test2 where

main = putStrLn "Hello World" -- write a string -- to the screen

{- f is a function which takes an integer and produces integer. {- this is an embedded comment -} the original comment extends to the matching end-comment token: -} f x = case x of     0 -> 1    -- 0 maps to 1 1 -> 5   -- 1 maps to 5 2 -> 2   -- 2 maps to 2 _ -> -1  -- everything else maps to -1 This example program shows the use of both line comments and (embedded) block comments.

Recursion
In imperative languages like C and Java, the most basic control structure is a loop (like a for loop). However, for loops don't make much sense in Haskell because they require destructive update (the index variable is constantly being updated). Instead, Haskell uses recursion.

A function is recursive if it calls itself (see the appendix on Recursion for more). Recursive functions exist also in C and Java but are used less than they are in functional languages. The prototypical recursive function is the factorial function. In an imperative language, you might write this as something like:

int factorial(int n) { int fact = 1; for (int i=2; i <= n; i++) fact = fact * i; return fact; } While this code fragment will successfully compute factorials for positive integers, it somehow ignores the basic definition of factorial, usually given as:

$$ n! = \begin{cases} 1 & n = 1 \\ n * (n-1)! & \mbox{otherwise}\\ \end{cases} $$

This definition itself is exactly a recursive definition: namely the value of $$n!$$ depends on the value of $$(n-1)!$$. If you think of $$!$$ as a function, then it is calling itself. We can translate this definition almost verbatim into Haskell code:

factorial 1 = 1 factorial n = n * factorial (n-1) This is likely the simplest recursive function you'll ever see, but it is correct.

Recursion can be a difficult thing to master. It is completely analogous to the concept of induction in mathematics (see the chapter Recursion for a more formal treatment of this). However, usually a problem can be thought of as having one or more base cases and one or more recursive-cases. In the case of, there is one base case (when $$n=1$$) and one recursive case (when $$n>1$$). For designing your own recursive algorithms, it is often useful to try to differentiate these two cases.

Turning now to the task of exponentiation, suppose that we have two positive integers $$a$$ and $$b$$, and that we want to calculate $$a^b$$. This problem has a single base case: namely when $$b$$ is $$1$$. The recursive case is when $$b>1$$. We can write a general form as:

$$ a^b = \begin{cases} a & b=1 \\ a * a^{b-1} & \mbox{otherwise} \\ \end{cases} $$

Again, this translates directly into Haskell code:

exponent a 1 = a exponent a b = a * exponent a (b-1) Just as we can define recursive functions on integers, so can we define recursive functions on lists. In this case, usually the base case is the empty list, and the recursive case is a cons list (i.e., a value consed on to another list).

Consider the task of calculating the length of a list. We can again break this down into two cases: either we have an empty list or we have a non-empty list. Clearly the length of an empty list is zero. Furthermore, if we have a cons list, then the length of this list is just the length of its tail plus one. Thus, we can define a length function as:

my_length [] = 0 my_length (x:xs) = 1 + my_length xs

Similarly, we can consider the  function. Again, the base case is the empty list, and the recursive case is a cons list. However, this time, we're choosing whether to keep an element, depending on whether or not a particular predicate holds. We can define the filter function as:

my_filter p [] = [] my_filter p (x:xs) = if p x   then x : my_filter p xs    else my_filter p xs In this code, when presented with an empty list, we simply return an empty list. This is because filter cannot add elements; it can only remove them.

When presented with a list of the form, we need to decide whether or not to keep the value. To do this, we use an <tt>if</tt> statement and the predicate. If  is true, then we return a list that begins with  followed by the result of filtering the tail of the list. If  is false, then we exclude and return the result of filtering the tail of the list.

We can also define  and both fold functions using explicit recursion. See the exercises for the definition of  and the chapter Language advanced for the folds.

Interactivity
If you are familiar with books on other (imperative) languages, you might be wondering why you haven't seen many of the standard programs written in tutorials of other languages (like ones that ask the user for his name and then says "Hi" to him by name). The reason for this is simple: Being a pure functional language, it is not entirely clear how one should handle operations like user input.

After all, suppose you have a function that reads a string from the keyboard. If you call this function twice, and the user types something the first time and something else the second time, then you no longer have a function, since it would return two different values. The solution to this was found in the depths of category theory, a branch of formal mathematics: monads. We're not yet ready to talk about monads formally, but for now, think of them simply as a convenient way to express operations like input/output. We'll discuss them in this context much more in the chapter Io and then discuss monads for monads' sake in the chapter Monads.

Suppose we want to write a function that's interactive. The way to do this is to use the <tt>do</tt> keyword. This allows us to specify the order of operations (remember that normally, since Haskell is a lazy language, the order in which operations are evaluated in it is unspecified). So, to write a simple program that asks a user for his name and then address him directly, enter the following code into "Name.hs":

module Main where

import System.IO

main = do hSetBuffering stdin LineBuffering putStrLn "Please enter your name: " name <- getLine putStrLn ("Hello, " ++ name ++ ", how are you?")

You can then either load this code in your interpreter and execute  by simply typing " ," or you can compile it and run it from the command line. I'll show the results of the interactive approach:

And there's interactivity. Let's go back and look at the code a little, though. We name the module "Main," so that we can compile it. We name the primary function " ," so that the compiler knows that this is the function to run when the program is run. On the fourth line, we import the  library, so that we can access the IO functions. On the seventh line, we start with <tt>do</tt>, telling Haskell that we're executing a sequence of commands.

The first command is, which you should probably ignore for now (incidentally, this is only required by GHC -- in Hugs you can get by without it). The necessity for this is because, when GHC reads input, it expects to read it in rather large blocks. A typical person's name is nowhere near large enough to fill this block. Thus, when we try to read from, it waits until it's gotten a whole block. We want to get rid of this, so we tell it to use instead of block buffering.

The next command is, which prints a string to the screen. On the ninth line, we say. This would normally be written, but using the arrow instead of the equal sign shows that  isn't a real function and can return different values. This command means "run the action, and store the results in  ."

The last line constructs a string using what we read in the previous line and then prints it to the screen.

Another example of a function that isn't really a function would be one that returns a random value. In this context, a function that does this is called. Using this, we can write a "guess the number" program. Enter the following code into "Guess.hs":

module Main where

import System.IO import System.Random

main = do hSetBuffering stdin LineBuffering num <- randomRIO (1::Int, 100) putStrLn "I'm thinking of a number between 1 and 100" doGuessing num

doGuessing num = do putStrLn "Enter your guess:" guess <- getLine let guessNum = read guess if guessNum < num then do putStrLn "Too low!" doGuessing num else if guessNum > num then do putStrLn "Too high!" doGuessing num else do putStrLn "You Win!" Let's examine this code. On the fifth line we write "import Random" to tell the compiler that we're going to be using some random functions (these aren't built into the Prelude). In the first line of, we ask for a random number in the range $$(1,100)$$. We need to write  to tell the compiler that we're using integers here -- not floating point numbers or other numbers. We'll talk more about this in the section on Type basics. On the next line, we tell the user what's going on, and then, on the last line of, we tell the compiler to execute the command.

The  function takes the number the user is trying to guess as an argument. First, it asks the user to guess and then accepts their guess (which is a ) from the keyboard. The <tt>if</tt> statement checks first to see if their guess is too low. However, since  is a string, and   is an integer, we first need to convert   to an integer by  ing it. Since " " is a plain, pure function (and not an IO action), we don't need to use the  notation (in fact, we cannot); we simply bind the value to. Note that while we're in <tt>do</tt> notation, we don't need <tt>in</tt>s for <tt>let</tt>s.

If they guessed too low, we inform them and then start over again. If they didn't guess too low, we check to see if they guessed too high. If they did, we tell them and start again. Otherwise, they didn't guess too low and they didn't guess too high, so they must have gotten it correct. We tell them that they won and exit. The fact that we exit is implicit in the fact that there are no commands following this. We don't need an explicit statement.

You can either compile this code or load it into your interpreter, and you will get something like:

The recursive action that we just saw doesn't actually return a value that we use in any way. In the case when it does, the "obvious" way to write the command is actually incorrect. Here, we will give the incorrect version, explain why it is wrong, then give the correct version.

Let's say we're writing a simple program that repeatedly asks the user to type in a few words. If at any point the user enters the empty word (i.e., he just hits enter without typing anything), the program prints out everything he's typed up until that point and then exits. The primary function (actually, an action) in this program is one that asks the user for a word, checks to see if it's empty, and then either continues or ends. The incorrect formulation of this might look something like:

askForWords = do putStrLn "Please enter a word:" word <- getLine if word == "" then return [] else return (word : askForWords) Before reading ahead, see if you can figure out what is wrong with the above code.

The error is on the last line, specifically with the term. Remember that when using, we are making a list out of an element (in this case ) and another list (in this case,  ). However,  is not a list; it is an action that, when run, will produce a list. That means that before we can attach anything to the front, we need to run the action and take the result. In this case, we want to do something like:

askForWords = do putStrLn "Please enter a word:" word <- getLine if word == "" then return [] else do     rest <- askForWords return (word : rest) Here, we first run, take the result and store it in the variable. Then, we return the list created from and.

By now, you should have a good understanding of how to write simple functions, compile them, test functions and programs in the interactive environment, and manipulate lists.

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Yet Another Haskell Tutorial/Type basics

Haskell uses a system of static type checking. This means that every expression in Haskell is assigned a type. For instance  would have type , for "character." Then, if you have a function which expects an argument of a certain type and you give it the wrong type, a compile-time error will be generated (that is, you will not be able to compile the program). This vastly reduces the number of bugs that can creep into your program.

Furthermore, Haskell uses a system of type inference. This means that you don't even need to specify the type of expressions. For comparison, in C, when you define a variable, you need to specify its type (for instance, int, char, etc.). In Haskell, you needn't do this -- the type will be inferred from context.

Both Hugs and GHCi allow you to apply type inference to an expression to find its type. This is done by using the  command. For instance, start up your favorite shell and try the following:

This tells us that the expression  has type   (the double colon   is used throughout Haskell to specify types).

Simple Types
There are a slew of built-in types, including  (for integers, both positive and negative),   (for floating point numbers),   (for single characters),   (for strings), and others. We have already seen an expression of type ; let's examine one of type  :

You can also enter more complicated expressions, for instance, a test of equality:

You should note that even though this expression is false, it still has a type, namely the type.

You can observe the process of type checking and type inference by trying to get the shell to give you the type of an ill-typed expression. For instance, the equality operator requires that the type of both of its arguments are of the same type. We can see that  and   are of different types by trying to compare a character to a string:

The first line of the error (the line containing " ") tells us the expression in which the type error occurred. The second line tells us which part of this expression is ill-typed. The third line tells us the inferred type of this term and the fourth line tells us what it needs to have matched. In this case, it says that type  doesn't match the type   (a list of characters -- a string in Haskell is represented as a list of characters).

As mentioned before, you can explicitly specify the type of an expression using the :: operator. For instance, instead of  in the previous example, we could have written. In this case, this has no effect since there's only one possible interpretation of. However, consider the case of numbers. You can try:

Here, we can see that the number 5 can be instantiated as either an  or a. What if we don't specify the type?

Not quite what you expected? What this means, briefly, is that if some type  is an instance of the   class, then type of the expression   can be of type. If that made no sense, that's okay for now. In Section Classes we talk extensively about type classes (which is what this is). The way to read this, though, is to say "a being an instance of Num implies a."

Polymorphic Types
Haskell employs a polymorphic type system. This essentially means that you can have type variables, which we have alluded to before. For instance, note that a function like  doesn't care what the elements in the list are:

This is possible because  has a polymorphic type:  $$\alpha$$  ->  $$\alpha$$. That means it can take as an argument any list and return a value which is a list of the same type.

The same analysis can explain the type of :

Here, GHCi has made explicit the universal quantification of the type values. That is, it is saying that for all types  and ,   is a function from   to.

Type Classes
We saw last section some strange typing having to do with the number five. Before we delve too deeply into the subject of type classes, let's take a step back and see some of the motivation.

Motivation
In many languages (C++, Java, etc.), there exists a system of overloading. That is, a function can be written that takes parameters of differing types. For instance, the canonical example is the equality function. If we want to compare two integers, we should use an integer comparison; if we want to compare two floating point numbers, we should use a floating point comparison; if we want to compare two characters, we should use a character comparison. In general, if we want to compare two things which have type $$\alpha$$, we want to use an $$\alpha-compare$$. We call $$\alpha$$ a type variable since it is a variable whose value is a type.

Unfortunately, this presents some problems for static type checking, since the type checker doesn't know which types a certain operation (for instance, equality testing) will be defined for. There are as many solutions to this problem as there are statically typed languages (perhaps a slight exaggeration, but not so much so). The one chosen in Haskell is the system of type classes. Whether this is the "correct" solution or the "best" solution of course depends on your application domain. It is, however, the one we have, so you should learn to love it.

Equality Testing
Returning to the issue of equality testing, what we want to be able to do is define a function  (the equality operator) which takes two parameters, each of the same type (call it $$\alpha$$), and returns a boolean. But this function may not be defined for every type; just for some. Thus, we associate this function  with a type class, which we call Eq. If a specific type $$\alpha$$ belongs to a certain type class (that is, all functions associated with that class are implemented for $$\alpha$$), we say that $$\alpha$$ is an instance of that class. For instance, Int is an instance of Eq since equality is defined over integers.

The Num Class
In addition to overloading operators like, Haskell has overloaded numeric constants (i.e., 1, 2, 3, etc.). This was done so that when you type in a number like 5, the compiler is free to say 5 is an integer or floating point number as it sees fit. It defines the Num class to contain all of these numbers and certain minimal operations over them (addition, for instance). The basic numeric types (Int, Double) are defined to be instances of Num.

We have only skimmed the surface of the power (and complexity) of type classes here. There will be much more discussion of them in Section Classes, but we need some more background before we can get there. Before we do that, we need to talk a little more about functions.

The Show Class
Another of the standard classes in Haskell is the  class. Types which are members of the  class have functions which convert values of that type to a string. This function is called. For instance  applied to the integer 5 is the string "5";   applied to the character 'a' is the three-character string "'a'" (the first and last characters are apostrophes). applied to a string simply puts quotes around it. You can test this in the interpreter:

Some types are not instances of Show; functions for example. If you try to show a function (like ), the compiler or interpreter will give you some cryptic error message, complaining about a missing instance declaration or an illegal class constraint.

Function Types
In Haskell, functions are first class values, meaning that just as  or   are values which have a type, so are functions like   or. Before we talk too much about functions, we need to make a short diversion into very theoretical computer science (don't worry, it won't be too painful) and talk about the lambda calculus.

Lambda Calculus
The name "Lambda Calculus", while perhaps daunting, describes a fairly simple system for representing functions. The way we would write a squaring function in lambda calculus is: $$\lambda x. x*x$$, which means that we take a value, which we will call $$x$$ (that's what $$\lambda x .$$ means) and then multiply it by itself. The $$\lambda$$ is called "lambda abstraction." In general, lambdas can only have one parameter. If we want to write a function that takes two numbers, doubles the first and adds it to the second, we would write: $$\lambda x \lambda y. 2*x+y$$. When we apply a value to a lambda expression, we remove the outermost $$\lambda$$ and replace every occurrence of the lambda variable with the value. For instance, if we evaluate $$(\lambda x . x*x) 5$$, we remove the lambda and replace every occurrence of $$x$$ with $$5$$, yielding $$(5*5)$$ which is $$25$$.

In fact, Haskell is largely based on an extension of the lambda calculus, and these two expressions can be written directly in Haskell (we simply replace the $$\lambda$$ with a backslash(\) and the $$.$$ with (->); also we don't need to repeat the lambdas; and, of course, in Haskell we have to give them names if we're defining functions):

square = \x -> x*x f = \x y -> 2*x + y

You can also evaluate lambda expressions in your interactive shell:

We can see in the second example that we need to give the lambda abstraction two arguments, one corresponding to  and the other corresponding to.

Higher-Order Types
"Higher-Order Types" is the name given to those types whose elements are functions. The type given to functions mimicks the lambda calculus representation of the functions. For instance, the definition of square gives $$\lambda x. x*x$$. To get the type of this, we first ask ourselves what the type of  is. Say we decide  is an. Then, we notice that the function  takes an   and produces a value. We know that when we multiply two s together, we get another , so the type of the results of   is also an. Thus, we say the type of  is.

We can apply a similar analysis to the function  above(\x y -> 2*x + y). The value of this function (remember, functions are values) is something which takes a value  and produces a new value, which takes a value   and produces. For instance, if we take  and apply only one number to it, we get $$(\lambda x \lambda y . 2x+y) 5$$ which becomes our new value $$\lambda y. 2(5)+y$$, where all occurrences of $$x$$ have been replaced with the applied value, $$5$$.

So we know that  takes an   and produces a value of some type, of which we're not sure. But we know the type of this value is the type of $$\lambda y. 2(5)+y$$. We apply the above analysis and find out that this expression has type. Thus,  takes an   and produces something which has type. So the type of  is.

This isn't entirely accurate. As we saw before, numbers like  aren't really of type , they are of type.

We can easily find the type of Prelude functions using ":t" as before:

We read this as: "head" is a function that takes a list containing values of type "a" and gives back a value of type "a"; "tail" takes a list of "a"s and gives back another list of "a"s; "null" takes a list of "a"s and gives back a boolean; "fst" takes a pair of type "(a,b)" and gives back something of type "a", and so on.

We can also get the type of operators like  and   and   and  ; however, in order to do this we need to put them in parentheses. In general, any function which is used infix (meaning in the middle of two arguments rather than before them) must be put in parentheses when getting its type.

The types of  and   are the same, and mean that   is a function which, for some type   which is an instance of , takes a value of type   and produces another function which takes a value of type   and produces a value of type. In short hand, we might say that  takes two values of type   and produces a value of type , but this is less precise.

The type of  means, in shorthand, that, for a given type ,   takes two lists of  s and produces a new list of  s. Similarly,   takes a value of type   and another value of type   (list of  s) and produces another value of type.

That Pesky IO Type
You might be tempted to try getting the type of a function like :

What in the world is that  thing? It's basically Haskell's way of representing that these functions aren't really functions. They're called "IO Actions" (hence the ). The immediate question which arises is: okay, so how do I get rid of the. Well, you can't maintain the pure functionality of your code while using a function with a type such as IO String -> String. Haskell's pure functions always give the same result when applied to the same argument, just as in mathematics. , on the other hand, yields whatever the file content happens to be when it is called. Suppose  at one point in an ongoing Haskell process, and later. That wouldn't be a problem in languages with mutable variables but in Haskell, once a value has been assigned to x, mutating that value could result in bizarre behavior prior to a system crash. So, in almost every use case you can imagine, the way to use things with an  type is to isolate them from pure parts of the program by combining them with other functions.

For example, if you're reading a file using, presumably you want to do something with the string it returns (otherwise, why would you read the file in the first place). Suppose you have a function  which takes a   and produces an. You can't directly apply  to the result of   since the input to   is   and the output of   is   and these don't match. However, you can combine these as:

main = do s <- readFile "somefile" let i = f s putStrLn (show i)

Here, we use the arrow convention to "get the string out of the IO action" and then apply  to the string (called  ). We then, for example, print  to the screen. Note that the let here doesn't have a corresponding in. This is because we are in a <tt>do</tt> block. Also note that we don't write  because   is just a normal function, not an IO action. Note:  can be simplified to   if you want.

Explicit Type Declarations
It is sometimes desirable to explicitly specify the types of some elements or functions, for one (or more) of the following reasons:

 * Clarity
 * Speed
 * Debugging

Some people consider it good software engineering to specify the types of all top-level functions. If nothing else, if you're trying to compile a program and you get type errors that you cannot understand, if you declare the types of some of your functions explicitly, it may be easier to figure out where the error is.

Type declarations are written separately from the function definition. For instance, we could explicitly type the function  as in the following code (an explicitly declared type is called a type signature):

square :: Num a => a -> a square x = x*x

These two lines do not even have to be next to each other. However, the type that you specify must match the inferred type of the function definition (or be more specific). In this definition, you could apply  to anything which is an instance of  : ,  , etc. However, if you knew apriori that   were only going to be applied to value of type  , you could refine its type as:

square :: Int -> Int square x = x*x

Now, you could only apply  to values of type. Moreover, with this definition, the compiler doesn't have to generate the general code specified in the original function definition since it knows you will only apply  to  s, so it may be able to generate faster code.

If you have extensions turned on ("-98" in Hugs or "-fglasgow-exts" in GHC(i)), you can also add a type signature to expressions and not just functions. For instance, you could write:

square (x :: Int) = x*x

which tells the compiler that  is an  ; however, it leaves the compiler alone to infer the type of the rest of the expression. What is the type of  in this example? Make your guess then you can check it either by entering this code into a file and loading it into your interpreter or by asking for the type of the expression:

since this lambda abstraction is equivalent to the above function declaration.

Functional Arguments
In the section on Lists we saw examples of functions taking other functions as arguments. For instance,  took a function to apply to each element in a list,   took a function that told it which elements of a list to keep, and   took a function which told it how to combine list elements together. As with every other function in Haskell, these are well-typed.

Let's first think about the  function. Its job is to take a list of elements and produce another list of elements. These two lists don't necessarily have to have the same types of elements. So  will take a value of type   and produce a value of type. How does it do this? It uses the user-supplied function to convert. In order to convert an  to a , this function must have type. Thus, the type of  is , which you can verify in your interpreter with ":t".

We can apply the same sort of analysis to  and discern that it has type. As we presented the  function, you might be tempted to give it type , meaning that you take a function which combines two  s into another one, an initial value of type  , a list of  s to produce a final value of type. In fact,  has a more general type:. So it takes a function which turn an  and a   into a , an initial value of type   and a list of  s. It produces a.

To see this, we can write a function  which counts how many members of a list satisfy a given constraint. You can of course use  and   to do this, but we will also do it using  :

module Count where

import Char

count1 bTest list = length (filter bTest list) count2 bTest list = foldr (\x cnt -> if bTest x then cnt+1 else cnt) 0 list

The functioning of  is simple. It filters the list  according to the predicate , then takes the length of the resulting list. On the other hand,  uses the initial value (which is an integer) to hold the current count. For each element in the list, it applies the lambda expression shown. This takes two arguments,  which holds the current count and   which is the current element in the list that we're looking at. It checks to see if  holds about. If it does, it returns the new value, increasing the count of elements for which the predicate holds. If it doesn't, it just returns, the old count. With  defined as above,   expands to.

Data Types
Tuples and lists are nice, common ways to define structured values. However, it is often desirable to be able to define our own data structures and functions over them. So-called "datatypes" are defined using the <tt>data</tt> keyword.

Pairs
For instance, a definition of a pair of elements (much like the standard, built-in pair type) could be:

data Pair a b = Pair a b

Let's walk through this code one word at a time. First we say "data" meaning that we're defining a datatype. We then give the name of the datatype, in this case, "Pair." The "a" and "b" that follow "Pair" are unique type parameters, just like the "a" is the type of the function. So up until this point, we've said that we're going to define a data structure called "Pair" which is parameterized over two types,  and. Note that you can't have  — in this case write.

After the equals sign, we specify the constructors of this data type. In this case, there is a single constructor, "Pair" (this doesn't necessarily have to have the same name as the type, but in the case of a single constructor it seems to make more sense). After this pair, we again write "a b", which means that in order to construct a  we need two values, one of type   and one of type.

This definition introduces a function,  that you can use to construct  s. If you enter this code into a file and load it, you can see how these are constructed:

So, by giving  two values, we have completely constructed a value of type. We can write functions involving pairs as:

pairFst (Pair x y) = x pairSnd (Pair x y) = y

In this, we've used the pattern matching capabilities of Haskell to look at a pair and extract values from it. In the definition of  we take an entire   and extract the first element; similarly for. We'll discuss pattern matching in much more detail in the section on Pattern matching.

Multiple Constructors
We have seen an example of the data type with one constructor: . It is also possible (and extremely useful) to have multiple constructors.

Let us consider a simple function which searches through a list for an element satisfying a given predicate and then returns the first element satisfying that predicate. What should we do if none of the elements in the list satisfy the predicate? A few options are listed below:

 * Raise an error
 * Loop indefinitely
 * Write a check function
 * Return the first element

Raising an error is certainly an option (see the section on Exceptions to see how to do this). The problem is that it is difficult/impossible to recover from such errors. Looping indefinitely is possible, but not terribly useful. We could write a sister function which checks to see if the list contains an element satisfying a predicate and leave it up to the user to always use this function first. We could return the first element, but this is very ad-hoc and difficult to remember; and what if the list itself is empty?

The fact that there is no basic option to solve this problem simply means we have to think about it a little more. What are we trying to do? We're trying to write a function which might succeed and might not. Furthermore, if it does succeed, it returns some sort of value. Let's write a datatype:

data Maybe a = Nothing | Just a

This is one of the most common datatypes in Haskell and is defined in the Prelude.

Here, we're saying that there are two possible ways to create something of type. The first is to use the nullary constructor, which takes no arguments (this is what "nullary" means). The second is to use the constructor , together with a value of type.

The  type is useful in all sorts of circumstances. For instance, suppose we want to write a function (like ) which returns the first element of a given list. However, we don't want the program to die if the given list is empty. We can accomplish this with a function like:

firstElement :: [a] -> Maybe a firstElement []    = Nothing firstElement (x:xs) = Just x

The type signature here says that  takes a list of s and produces something with type. In the first line of code, we match against the empty list. If this match succeeds (i.e., the list is, in fact, empty), we return. If the first match fails, then we try to match against  which must succeed. In this case, we return.

For our  function, we represent failure by the value and success with value  by. Our function might look something like this:

findElement :: (a -> Bool) -> [a] -> Maybe a findElement p [] = Nothing findElement p (x:xs) = if p x then Just x   else findElement p xs

The first line here gives the type of the function. In this case, our first argument is the predicate (and takes an element of type and returns   if and only if the element satisfies the predicate); the second argument is a list of  s. Our return value is maybe an. That is, if the function succeeds, we will return  and if not,.

Another useful datatype is the  type, defined as:

data Either a b = Left a               | Right b

This is a way of expressing alternation. That is, something of type is either a value of type  (using the  constructor) or a value of type   (using the  constructor).

Recursive Datatypes
We can also define recursive datatypes. These are datatypes whose definitions are based on themselves. For instance, we could define a list datatype as:

data List a = Nil | Cons a (List a)

In this definition, we have defined what it means to be of type . We say that a list is either empty or it's the   of a value of type   and another value of type . This is almost identical to the actual definition of the list datatype in Haskell, except that uses special syntax where corresponds to  and   corresponds to. We can write our own  function for our lists as:

listLength Nil = 0 listLength (Cons x xs) = 1 + listLength xs

This function is slightly more complicated and uses recursion to calculate the length of a. The first line says that the length of an empty list (a ) is $$0$$. This much is obvious. The second line tells us how to calculate the length of a non-empty list. A non-empty list must be of the form  for some values of  and. We know that  is another list and we know that whatever the length of the current list is, it's the length of its tail (the value of ) plus one (to account for ). Thus, we apply the   function to   and add one to the result. This gives us the length of the entire list.

Binary Trees
We can define datatypes that are more complicated than lists. Suppose we want to define a structure that looks like a binary tree. A binary tree is a structure that has a single root node; each node in the tree is either a "leaf" or a "branch." If it's a leaf, it holds a value; if it's a branch, it holds a value and a left child and a right child. Each of these children is another node. We can define such a data type as:

data BinaryTree a   = Leaf a    | Branch (BinaryTree a) a (BinaryTree a)

In this datatype declaration we say that a  of  s is either a   which holds an , or it's a branch with a left child (which is a   of  s), a node value (which is an ), and a right child (which is also a  of  s). It is simple to modify the function so that instead of calculating the length of lists, it calculates the number of nodes in a. Can you figure out how? We can call this function. The solution is given below:

treeSize (Leaf x) = 1 treeSize (Branch left x right) = 1 + treeSize left + treeSize right

Here, we say that the size of a leaf is $$1$$ and the size of a branch is the size of its left child, plus the size of its right child, plus one.

Enumerated Sets
You can also use datatypes to define things like enumerated sets, for instance, a type which can only have a constrained number of values. We could define a color type:

data Color = Red | Orange | Yellow | Green | Blue | Purple | White | Black

This would be sufficient to deal with simple colors. Suppose we were using this to write a drawing program, we could then write a function to convert between a  and a RGB triple. We can write a function, as:

colorToRGB Red   = (255,0,0) colorToRGB Orange = (255,128,0) colorToRGB Yellow = (255,255,0) colorToRGB Green = (0,255,0) colorToRGB Blue  = (0,0,255) colorToRGB Purple = (255,0,255) colorToRGB White = (255,255,255) colorToRGB Black = (0,0,0)

If we wanted also to allow the user to define his own custom colors, we could change the  datatype to something like:

data Color = Red | Orange | Yellow | Green | Blue | Purple | White | Black | Custom Int Int Int -- R G B components

And add a final definition for :

colorToRGB (Custom r g b) = (r,g,b)

The Unit type
A final useful datatype defined in Haskell (from the Prelude) is the unit type. Its definition is:

data =

The only true value of this type is. This is essentially the same as a void type in a language like C or Java and will be useful when we talk about IO in the chapter Io.

We'll dwell much more on data types in the sections on Pattern matching and Datatypes.

Continuation Passing Style
There is a style of functional programming called "Continuation Passing Style" (also simply "CPS"). The idea behind CPS is to pass around as a function argument what to do next. I will handwave through an example which is too complex to write out at this point and then give a real example, though one with less motivation.

Consider the problem of parsing. The idea here is that we have a sequence of tokens (words, letters, whatever) and we want to ascribe structure to them. The task of converting a string of Java tokens to a Java abstract syntax tree is an example of a parsing problem. So is the task of parsing English sentences (though the latter is extremely difficult, even for native English users parsing sentences from the real world).

Suppose we're parsing something like C or Java where functions take arguments in parentheses. But for simplicity, assume they are not separated by commas. That is, a function call looks like <tt>myFunction(x y z)</tt>. We want to convert this into something like a pair containing first the string "myFunction" and then a list with three string elements: "x", "y" and "z".

The general approach to solving this would be to write a function which parses function calls like this one. First it would look for an identifier ("myFunction"), then for an open parenthesis, then for zero or more identifiers, then for a close parenthesis.

One way to do this would be to have two functions:

parseFunction  :: [Token] -> Maybe ((String, [String]), [Token])

parseIdentifier :: [Token] -> Maybe (String, [Token])

The idea would be that if we call, if it doesn't return  , then it returns the pair described earlier, together with whatever is left after parsing the function. Similarly, will parse one of the arguments. If it returns , then it's not an argument; if it returns something, then that something is the argument paired with the rest of the tokens.

What the  function would do is to parse an identifier. If this fails, it fails itself. Otherwise, it continues and tries to parse an open parenthesis. If that succeeds, it repeatedly calls  until that fails. It then tries to parse a close parenthesis. If that succeeds, then it's done. Otherwise, it fails.

There is, however, another way to think about this problem. The advantage to this solution is that functions no longer need to return the remaining tokens (which tends to get ugly). Instead of the above, we write functions:

parseFunction  :: [Token] -> ((String, [String]) -> [Token] -> a) -> ([Token] -> a) -> a

parseIdentifier :: [Token] -> (String -> [Token] -> a) -> ([Token] -> a) -> a

Let's consider. This takes three arguments: a list of tokens and two continuations. The first continuation is what to do when you succeed. The second continuation is what to do if you fail. What  does, then, is try to read an identifier. If this succeeds, it calls the first continuation with that identifier and the remaining tokens as arguments. If reading the identifier fails, it calls the second continuation with all the tokens.

Now consider. Recall that it wants to read an identifier, an open parenthesis, zero or more identifiers and a close parenthesis. Thus, the first thing it does is call . The first argument it gives is the list of tokens. The first continuation (which is what should do if it succeeds) is in turn a function which will look for an open parenthesis, zero or more arguments and a close parenthesis. The second continuation (the failure argument) is just going to be the failure function given to.

Now, we simply need to define this function which looks for an open parenthesis, zero or more arguments and a close parenthesis. This is easy. We write a function which looks for the open parenthesis and then calls  with a success continuation that looks for more identifiers, and a "failure" continuation which looks for the close parenthesis (note that this failure doesn't really mean failure -- it just means there are no more arguments left).

I realize this discussion has been quite abstract. I would willingly give code for all this parsing, but it is perhaps too complex at the moment. Instead, consider the problem of folding across a list. We can write a CPS fold as:

cfold' f z [] = z cfold' f z (x:xs) = f x z (\y -> cfold' f y xs)

In this code,  takes a function   which takes three arguments, slightly different from the standard folds. The first is the current list element,, the second is the accumulated element,, and the third is the continuation: basically, what to do next.

We can write a wrapper function for  that will make it behave more like a normal fold:

cfold f z l = cfold' (\x t g -> f x (g t)) z l

We can test that this function behaves as we desire:

One thing that's nice about formulating  in terms of the helper function  is that we can use the helper function directly. This enables us to change, for instance, the evaluation order of the fold very easily:

The only difference between these calls to  is whether we call the continuation before or after constructing the list. As it turns out, this slight difference changes the behavior for being like to being like. We can evaluate both of these calls as follows (let  be the folding function):

cfold' (\x t g -> (x : g t)) [] [1,2,3] ==> cfold' f [] [1,2,3] ==> f 1 [] (\y -> cfold' f y [2,3]) ==> 1 : ((\y -> cfold' f y [2,3]) []) ==> 1 : (cfold' f [] [2,3]) ==> 1 : (f 2 [] (\y -> cfold' f y [3])) ==> 1 : (2 : ((\y -> cfold' f y [3]) [])) ==> 1 : (2 : (cfold' f [] [3])) ==> 1 : (2 : (f 3 [] (\y -> cfold' f y []))) ==> 1 : (2 : (3 : (cfold' f [] []))) ==> 1 : (2 : (3 : [])) ==>  [1,2,3]

cfold' (\x t g -> g (x:t)) [] [1,2,3] ==> cfold' f [] [1,2,3] ==> (\x t g -> g (x:t)) 1 [] (\y -> cfold' f y [2,3]) ==> (\g -> g [1]) (\y -> cfold' f y [2,3]) ==> (\y -> cfold' f y [2,3]) [1] ==> cfold' f [1] [2,3] ==> (\x t g -> g (x:t)) 2 [1] (\y -> cfold' f y [3]) ==> cfold' f (2:[1]) [3] ==> cfold' f [2,1] [3] ==> (\x t g -> g (x:t)) 3 [2,1] (\y -> cfold' f y []) ==> cfold' f (3:[2,1]) [] ==> [3,2,1]

In general, continuation passing style is a very powerful abstraction, though it can be difficult to master. We will revisit the topic more thoroughly later in the book.


text:
Yet Another Haskell Tutorial/Io

As we mentioned earlier, it is difficult to think of a good, clean way to integrate operations like input/output into a pure functional language. Before we give the solution, let's take a step back and think about the difficulties inherent in such a task.

Any IO library should provide a host of functions, containing (at a minimum) operations like:

 * print a string to the screen
 * read a string from a keyboard
 * write data to a file
 * read data from a file

There are two issues here. Let's first consider the initial two examples and think about what their types should be. Certainly the first operation (I hesitate to call it a "function") should take a argument and produce something, but what should it produce? It could produce a unit, since there is essentially no return value from printing a string. The second operation, similarly, should return a, but it doesn't seem to require an argument.

We want both of these operations to be functions, but they are by definition not functions. The item that reads a string from the keyboard cannot be a function, as it will not return the same every time. And if the first function simply returns every time, there should be no problem with replacing it with a function, due to referential transparency. But clearly this does not have the desired effect.

The RealWorld Solution
In a sense, the reason that these items are not functions is that they interact with the "real world." Their values depend directly on the real world. Supposing we had a type, we might write these functions as having type:

printAString :: RealWorld -> String -> RealWorld readAString :: RealWorld -> (RealWorld, String) That is,  takes a current state of the world and a string to print; it then modifies the state of the world in such a way that the string is now printed and returns this new value. Similarly, takes a current state of the world and returns a new state of the world, paired with the  that was typed.

This would be a possible way to do IO, though it is more than somewhat unwieldy. In this style (assuming an initial  state were an argument to  ), our "Name.hs" program from the section on Interactivity would look something like:

main rW = let rW' = printAString rW "Please enter your name: " (rW'',name) = readAString rW' in printAString rW'' ("Hello, " ++ name ++ ", how are you?") This is not only hard to read, but prone to error, if you accidentally use the wrong version of the. It also doesn't model the fact that the program below makes no sense:

main rW = let rW' = printAString rW "Please enter your name: " (rW'',name) = readAString rW' in printAString rW'                 -- OOPS! ("Hello, " ++ name ++ ", how are you?") In this program, the reference to  on the last line has been changed to a reference to. It is completely unclear what this program should do. Clearly, it must read a string in order to have a value for  to be printed. But that means that the has been updated. However, then we try to ignore this update by using an "old version" of the. There is clearly something wrong happening here.

Suffice it to say that doing IO operations in a pure lazy functional language is not trivial.

Actions
The breakthrough for solving this problem came when Phil Wadler realized that monads would be a good way to think about IO computations. In fact, monads are able to express much more than just the simple operations described above; we can use them to express a variety of constructions like concurrence, exceptions, IO, non-determinism and much more. Moreover, there is nothing special about them; they can be defined within Haskell with no special handling from the compiler (though compilers often choose to optimize monadic operations).

As pointed out before, we cannot think of things like "print a string to the screen" or "read data from a file" as functions, since they are not (in the pure mathematical sense). Therefore, we give them another name: actions. Not only do we give them a special name, we give them a special type. One particularly useful action is, which prints a string to the screen. This action has type:

putStrLn :: String -> IO As expected,  takes a string argument. What it returns is of type. This means that this function is actually an action (that is what the  means). Furthermore, when this action is evaluated (or "run"), the result will have type .

You can probably already guess the type of :

getLine :: IO String This means that  is an IO action that, when run, will have type.

The question immediately arises: "how do you `run' an action?". This is something that is left up to the compiler. You cannot actually run an action yourself; instead, a program is, itself, a single action that is run when the compiled program is executed. Thus, the compiler requires that the  function have type , which means that it is an IO action that returns nothing. The compiled code then executes this action.

However, while you are not allowed to run actions yourself, you are allowed to  actions. In fact, we have already seen one way to do this using the do notation (how to really do this will be revealed in the chapter Monads). Let's consider the original name program:

main = do hSetBuffering stdin LineBuffering putStrLn "Please enter your name: " name <- getLine putStrLn ("Hello, " ++ name ++ ", how are you?") We can consider the do notation as a way to combine a sequence of actions. Moreover, the  notation is a way to get the value out of an action. So, in this program, we're sequencing four actions: setting buffering, a, a   and another . The   action has type  , so we provide it a, so the fully applied action has type . This is something that we are allowed to execute.

The  action has type , so it is okay to execute it directly. However, in order to get the value out of the action, we write, which basically means "run , and put the results in the variable called  ."

Normal Haskell constructions like if/then/else and case/of can be used within the do notation, but you need to be somewhat careful. For instance, in our "guess the number" program, we have:

do ... if (read guess) < num then do putStrLn "Too low!" doGuessing num else if read guess > num then do putStrLn "Too high!" doGuessing num else do putStrLn "You Win!" If we think about how the if/then/else construction works, it essentially takes three arguments: the condition, the "then" branch, and the "else" branch. The condition needs to have type , and the two branches can have any type, provided that they have the same type. The type of the entire if/then/else construction is then the type of the two branches.

In the outermost comparison, we have  as the condition. This clearly has the correct type. Let's just consider the "then" branch. The code here is:

do putStrLn "Too low!" doGuessing num Here, we are sequencing two actions:  and . The first has type , which is fine. The second also has type, which is fine. The type result of the entire computation is precisely the type of the final computation. Thus, the type of the "then" branch is also. A similar argument shows that the type of the "else" branch is also . This means the type of the entire if/then/else construction is, which is just what we want.

It is incorrect to think to yourself "Well, I already started a <tt>do</tt> block; I don't need another one," and hence write something like:

do if (read guess) < num then putStrLn "Too low!" doGuessing num else ... Here, since we didn't repeat the <tt>do</tt>, the compiler doesn't know that the  and   calls are supposed to be sequenced, and the compiler will think you're trying to call with three arguments: the string, the function and the integer. It will certainly complain (though the error may be somewhat difficult to comprehend at this point).

We can write the same  function using a <tt>case</tt> statement. To do this, we first introduce the Prelude function , which takes two values of the same type (in the class) and returns one of ,  ,  , depending on whether the first is greater than, less than or equal to the second.

doGuessing num = do putStrLn "Enter your guess:" guess <- getLine case compare (read guess) num of   LT -> do putStrLn "Too low!" doGuessing num GT -> do putStrLn "Too high!" doGuessing num EQ -> putStrLn "You Win!" Here, again, the <tt>do</tt>s after the s are necessary on the first two options, because we are sequencing actions.

If you're used to programming in an imperative language like C or Java, you might think that <tt>return</tt> will exit you from the current function. This is not so in Haskell. In Haskell, <tt>return</tt> simply takes a normal value (for instance, one of type ) and makes it into an action that returns the given value (for instance, the value of type ). In particular, in an imperative language, you might write this function as:

void doGuessing(int num) { print "Enter your guess:"; int guess = atoi(readLine); if (guess == num) { print "You win!"; return ; }

// we won't get here if guess == num if (guess < num) { print "Too low!"; doGuessing(num); } else { print "Too high!"; doGuessing(num); } } Here, because we have the  in the first   match, we expect the code to exit there (and in most imperative languages, it does). However, the equivalent code in Haskell, which might look something like:

doGuessing num = do putStrLn "Enter your guess:" guess <- getLine case compare (read guess) num of   EQ -> do putStrLn "You win!" return

-- we don't expect to get here unless guess == num if (read guess < num) then do putStrLn "Too low!"; doGuessing num else do putStrLn "Too high!"; doGuessing num will not behave as you expect. First of all, if you guess correctly, it will first print "You win!," but it won't exit, and it will check whether  is less than. Of course it is not, so the else branch is taken, and it will print "Too high!" and then ask you to guess again.

On the other hand, if you guess incorrectly, it will try to evaluate the case statement and get either  or   as the result of the. In either case, it won't have a pattern that matches, and the program will fail immediately with an exception.

The IO Library
The IO Library (available by <tt>import</tt>ing the  module) contains many definitions, the most common of which are listed below:

data IOMode = ReadMode   | WriteMode | AppendMode | ReadWriteMode

openFile    :: FilePath -> IOMode -> IO Handle hClose      :: Handle -> IO

hIsEOF      :: Handle -> IO Bool

hGetChar    :: Handle -> IO Char hGetLine    :: Handle -> IO String hGetContents :: Handle -> IO String

getChar     :: IO Char getLine     :: IO String getContents :: IO String

hPutChar    :: Handle -> Char -> IO hPutStr     :: Handle -> String -> IO hPutStrLn   :: Handle -> String -> IO

putChar     :: Char -> IO putStr      :: String -> IO putStrLn    :: String -> IO

readFile    :: FilePath -> IO String writeFile   :: FilePath -> String -> IO

bracket     :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c

Most of these functions are self-explanatory. The  and functions open and close a file, respectively, using the argument as the mode for opening the file. tests for end-of file. and  read a character or line (respectively) from a file. reads the entire file. The,   and variants read from standard input. prints a character to a file;  prints a string; and prints a string with a newline character at the end. The variants without the  prefix work on standard output. The and  functions read an entire file without having to open it first.

The  function is used to perform actions safely. Consider a function that opens a file, writes a character to it, and then closes the file. When writing such a function, one needs to be careful to ensure that, if there were an error at some point, the file is still successfully closed. The  function makes this easy. It takes three arguments: The first is the action to perform at the beginning. The second is the action to perform at the end, regardless of whether there's an error or not. The third is the action to perform in the middle, which might result in an error. For instance, our character-writing function might look like:

writeChar :: FilePath -> Char -> IO writeChar fp c = bracket (openFile fp ReadMode) hClose (\h -> hPutChar h c) This will open the file, write the character and then close the file. However, if writing the character fails,  will still be executed, and the exception will be reraised afterwards. That way, you don't need to worry too much about catching the exceptions and about closing all of your handles.

A File Reading Program
We can write a simple program that allows a user to read and write files. The interface is admittedly poor, and it does not catch all errors (try reading a non-existent file). Nevertheless, it should give a fairly complete example of how to use IO. Enter the following code into "FileRead.hs," and compile/run:

module Main where

import System.IO import Control.Exception

main = do hSetBuffering stdin LineBuffering doLoop

doLoop = do putStrLn "Enter a command rFN wFN or q to quit:" command <- getLine case command of   'q':_ -> return 'r':filename -> do putStrLn ("Reading " ++ filename) doRead filename doLoop 'w':filename -> do putStrLn ("Writing " ++ filename) doWrite filename doLoop _           -> doLoop

doRead filename = bracket (openFile filename ReadMode) hClose (\h -> do contents <- hGetContents h                     putStrLn "The first 100 chars:"                      putStrLn (take 100 contents))

doWrite filename = do putStrLn "Enter text to go into the file:" contents <- getLine bracket (openFile filename WriteMode) hClose (\h -> hPutStrLn h contents) What does this program do? First, it issues a short string of instructions and reads a command. It then performs a <tt>case</tt> switch on the command and checks first to see if the first character is a `q.' If it is, it returns a value of unit type.

If the first character of the command wasn't a `q,' the program checks to see if it was an 'r' followed by some string that is bound to the variable. It then tells you that it's reading the file, does the read and runs  again. The check for `w' is nearly identical. Otherwise, it matches, the wildcard character, and loops to.

The  function uses the   function to make sure there are no problems reading the file. It opens a file in, reads its contents and prints the first 100 characters (the  function takes an integer $$n$$ and a list and returns the first $$n$$ elements of the list).

The  function asks for some text, reads it from the keyboard, and then writes it to the file specified.

The only major problem with this program is that it will die if you try to read a file that doesn't already exists or if you specify some bad filename like. You may think that the calls to  in   and   should take care of this, but they don't.  They only catch exceptions within the main body, not within the startup or shutdown functions ( and, in these cases). We would need to catch exceptions raised by, in order to make this complete. We will do this when we talk about exceptions in more detail in the section on Exceptions.

title: Yet Another Haskell Tutorial/Io