CS 224 Lab 0Getting up to speed in Haskell

Objectives

  • Write simple Haskell functions
  • Use lists in Haskell
  • Use pattern matching facilities in Haskell
  • Perform the following tasks in the order given.

    1. For your very first session you will have to do a one-time setup of the Eclipse Haskell plug-in. Click the Configurator wizard button (fp) on the toolbar.  Enter (or use the Browse option) C:\ghc\ghc-6.8.2\bin\ghc.exe as the path to the GHC executable.  Click Next twice (ignoring Haddock).  Enter C:\Program Files\WinHugs\hugs.exe as the the path to the HUGS executable.  Click Finish.
       
    2. Download the Lab0 project and import it into Eclipse as a Haskell project (select Haskell as the Perspective under the Window directory).
       
    3. To compile the Example0 code, open it in the editor, select Run As... and then select Hugs 98 session. 
       
    4. Whenever we define a function we usually declare the type of that function.  That is, we specify the types of the parameters as well as the type of the returned value.

      fact  :: Integer -> Integer

      gcd :: Integer -> Integer -> Integer

       

      Observe that the function fact takes a parameter which is an Integer and returns a value which is an Integer.  We denote the type of this function therefore as Integer -> Integer.  

      Note that the function gcd takes two Integers as parameters and returns an Integer.  We will discuss later why the type for that function is written so strangely as
      Integer -> Integer -> Integer.

      Take a look at the recursive definitions of these two functions.
       

    5. In the console window you will see the prompt at which you can type Haskell expressions.  Try the expressions:
              fact 5
              gcd 15 10
       
    6.  Lists are written in square brackets and all elements in the list must be the same type.  Here are some examples given with their types:

      [1,2,3]  :: [Int]

      ['h', 'e', 'l' ,'l','o']  :: [Char]

      [[1,2], [3]]  :: [[Int]]

      [(+), (*)]  :: [Int->Int->Int]

      A list with no elements is written as [] and pronounced "nil".  To add a single element x to the front of a list xs, we write x : xs.  In actuality the list [1,2,3] is equivalent to 1 : (2 : (3 : [])).

      Take a look at the definitions of the functions len and nth which compute the length of a list and the nth value in a list.    Observe the types of these functions. The type [a] represents a list of any type.  Notice how the definitions use cases for the form of the arguments.

      Try the expressions:
              len [2, 6, 12]
              nth 2 [6,7,8,9]
       


    7.  
      Assignment:
      Write the function member  :: (Eq a) => Integer -> [a] -> Bool which returns the boolean value True or False depending on if the Integer parameter is contained in the list.

           member 2 [1, 2, 3, 4]  => True
           member 5 [1, 2, 3, 4]  => False

      Note that the specification (Eq a) indicates that the type a must be a type on which we can perform the == relation.


       


    8.  
      Assignment:
      Write the function double  :: [a] -> [a] which returns a list with each member of the parameter repeated twice.

          double [1, 2, 3] => [1,1,2,2,3,3]
       


       

    9. We can create user defined data types.  For example, a data type which defines geometric shapes that can either be a rectangle or an ellipse is given as follows:

      data Shape =     Rectangle Side Side
                              |   Ellipse Radius Radius
          deriving Show

      type Radius = Float
      type Side = Float

      This says that a Shape can be either a Rectangle, where two sides are given as parameters, or an Ellipse where two radius values are provided.  We then use type synonyms to specify that the Side and Radius types are each Floats.  The specification "deriving Show" is just a way to let Haskell be able to print out values of this type.

      If we want to create a rectangle, r1,  with one side of length 2.0 and another of length 3.5 we would use:

      r1= Rectangle 2.0 3.5

      We now want a selector which will compute the area of a shape object. We define the function area for its behavior on each of the Shape constructors:

      area :: Shape -> Float
      area (Rectangle s1 s2) = s1*s2
      area (Ellipse r1 r2) = pi*r1*r2

      We could find the area of our rectangle r1:

      area r1

    10. Suppose we wish to define a binary search tree.  Recall that in a binary search tree, each node will contain a value and the elements are arranged so that all elements smaller than the node value are in the left sub-tree and all elements larger than the node value are in the right sub-tree.

      We can define the data type Bst :

          
      data Bst a = Null | Branch a (Bst a) (Bst a)

      The tree contains some type a, and a tree can either be empty (Null) or be a node (Branch) containing a value of type a and two binary search trees representing the left and right sub-trees.
       


    11.  

      Assignment:
      Complete the function insert :: (Ord a) => a -> Bst a -> Bst a
      which inserts a value into a binary search tree in the proper position, returning the new binary search tree. 

      Note that the specification (Ord a) indicates that the type a must be a type on which we can perform < , ==, and > relations.

         insert x Null = ___________________
          insert x (Branch n left right) = 
               if x < n then _______________________
               else if x > n then ______________________
               else ____________________________

      Test your function on the Bst, testbst , which is provided in the Example0 file.


       

    12.  
       
      Assignment:
      Write the function deleteMin  :: Bst a  -> Bst a which returns a binary search tree with the smallest element removed.
       


       

    13. Send me your modified zipped project in the dropbox in BlackBoard.