You will be using Haskell98, the 1998 standardization of Haskell in this course. We will be using the GHCi Haskell interpreter.
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.)
The file test.hs is loaded and type checked by GHCi. Don't worry about what test.hs contains, this is not important to the example which is about showing that GHCi can be started up with an input file. Note also that GHCi can be started up without an input file.ngopalan@csel-kh4240-01 (~) % 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 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.)
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> 2 + 3 5 *Main> head [1,2,3,4] 1
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.*Main> :type ['a', 'b', 'c'] ['a','b','c'] :: [Char] *Main> :type head head :: [a] -> a
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:
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 error, make them available for use.app [ ] l = l app (a:l1) l2 = a : (app l1 l2)
After the function definition has been loaded, we can query the type of app:
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> :type app app :: [a] -> [a] -> [a]
GHCi evaluates the expression and prints the expected list as the results.*Main> app [1, 2] [3, 4] [1,2,3,4]
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.*Main> :type 1 1 :: Num a => a
There are several primitive numeric types that 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.