Using Haskell

CSci 5106: Programming Languages

We will be using the GHCi Haskell interpreter. To use this, you will need to load the module soft/haskell. Load this module the same way you loaded the ML module. Modules are discussed here.

GHCi, like the Scheme and ML interpreters, provides an interactive environment for evaluating Haskell expressions as an interaction loop (similar to the read-eval-print loop of Scheme, explained here. In GHCi, however, you cannot define new functions or values in the interpreter. You must define them in a file and load that file into GHCi.

(The phrases you are expected to type appear in blue below.)

evw@mega% ghci test.hs GHCi, version 7.10.3: http://www.haskell.org/ghc/ :? for help [1 of 1] Compiling Main ( test.hs, interpreted ) Ok, modules loaded: Main. *Main>

The file test.hs is loaded and type checked by GHCi. GHCi can also be started up without an input file.

The prompt *Main> indicates that GHCi is ready to evaluate a Haskell expression. (Main is the name of the module defined in test.hs. If GHCi is started without an input file, the module Prelude is used.)

*Main> 2 + 3 5 *Main> head [1,2,3,4] 1

GHCi evaluates the expression typed by the user after the "return" or "enter" key is pressed. The resulting value is then printed. A handy feature of GHCi is its capability of displaying the type of any Haskell expression using the :type command. For example,

*Main> :type ['a', 'b', 'c'] ['a','b','c'] :: [Char] *Main> :type head head :: [a] -> a

As in the other languages we have studied, you'll want to keep your Haskell function and value definitions in a file. When writing Haskell programs, it is convenient to have one window for the GHCi session and another window for the editor to edit the file containing your function definitions. To reload the function definitions stored in the current module (as indicated by the module name in the prompt) type :reload or equivalently :r. To load function definitions in a different file, type :load filename.

For more information on the Haskell language, I suggest that you look at A Gentle Introduction to Haskell and the introduction to Haskell on the Haskell web page.

Let us now develop a Haskell version of the list append function app that we previously developed in ML.

In the file app.hs type the following definition we discussed in class:

app [ ] l = l app (a:l1) l2 = a : (app l1 l2)

Load the function definitions in this file into GHCi by either starting GHCi with the file name, that is, at the command-line type ghci app.hs or load it into GHCi after GHCi has been started by typing :load app.hs. GHCi will type-check all the definitions in the file and, if there are no errors, make them available for use.

After the function definition has been loaded, we can query the type of app:

*Main> :type app app :: [a] -> [a] -> [a]

The type expressions here are slightly different from those in ML. Here, type variables are not prefixed by the single quote (') as they are in ML. Also, the type of a list of elements is written as the type of the elements in between square brackets, as in [Char] and [a] above. We may then use this function in the following expression:

*Main> app [1, 2] [3, 4] [1,2,3,4]

GHCi evaluates the expression and prints the expected list as the results.

A note on type classes

Consider the following GHCi session:

*Main> :type 1 1 :: Num a => a

This rather bewildering type expression Num a => a says that if the type variable a is an element of the Num type class, then the type of the expression 1 is a.

There are several primitive numeric types are elements of this class, including Int, the standard integer type; Integer, infinite precision integers; Float, for floating point values.

The idea is that 1 could have any one of those types.

For now, we won't be using type classes but since the types of some simple expressions, like 1 may have them you should at least know what they are. More details can be found in the Gentle Introduction to Haskell mentioned above.