CS 291 University of Puget Sound Spring, 2020
 
Programming Language Paradigms:
Explorations with Functional Problem Solving (supported by Scheme/Haskell)
and Declarative Prblem Solving (supported by Prolog)
 

Haskell Worksheet 2, due Monday, March 2

Table Comparing Scheme and Haskell Conditionals/Patterns

  Scheme Language Haskell
Topic Syntax Example Comparison(s) Syntax Example
multiple conditions within a function cond expressions provide a sequence of tests and actions
(define f
  (lambda (x)
    (cond ((< x 0) "negative")
          ((= x 0) "zero")
          (else "positive"))))
        
Guards in Haskell tied to definition of function Guards identify a sequence of patterns, see Guards, Guards!
    f x
       |x < 0 = "negative"
       |x == 0   = "zero"
       |otherwise = "positive"
        

Two examples for determining the maximum value on a list.

(This is similar to the library min function in Scheme and duplicates and maximum in Haskell.)


    (define mymax
       (lambda (lst)
           (mymax-kernel (car lst) (cdr lst))
    )  )
    (define mymax-kernel
       (lambda (max-so-far rest)
          (cond ((null? rest) max-so-far)
                ((< max-so-far (car rest))
                    (mymax-kernel (car rest) (cdr rest)))
                (else (mymax-kernel max-so-far (cdr rest)))
    )  )  )
  myMax lst = myMaxKernel (head lst)  (tail lst)

  myMaxKernel maxSoFar rest
    | rest == [ ] = 7
    | maxSoFar < (head rest)
           = myMaxKernel (head rest) (tail rest)
    | otherwise = myMaxKernel maxSoFar (tail rest)

Problems for this Worksheet 2 with Haskell

This worksheet continues the transition from working with functional problem solving with Scheme to functional problem solving with Haskell. Thus, this lab considers problem done previously in Scheme. For this lab,

  1. Consider a function myMaximum that determines the `maximum value on a list of numbers.

    1. Write code for this function. (This problem asks you to write you own implementation of Haskell's a pre-defined function maximum.)
    2. Identify the type of this function (based on the reading on types). Briefly explain why this type is appropriate for this function.
  2. Write two versions of a function countdown that takes any non-negative integer start as its argument returns a list of all the positive integers less than or equal to start, in descending order:

       countdown 5 ===> [5 4 3 2 1]
       countdown 1 ===> [1]
       countdown 0 ===> [ ]
        
    1. As a first version, write countdown using [tail] recursion with a separate kernel procedure.
    2. As an alternative, write countdownAlt that uses Haskell's list declarations and list functions directly, so the function can be done on one line.
  3. Consider Haskell's library function replicate that takes two arguments, size and an item (of any type), and returns a list of size elements, each of which is item:

    1. Write a basic (non-tail-recursive] procedure myReplicate that gives your own implementation of the replicate function.
        myReplicate 6 "foo"    ===>  ["foo", "foo", "foo", "foo", "foo", "foo"]
        myReplicate 2 "string" ===>  ["string" "string"]
        myReplicate 1 "one"    ===>  ["one"]
        myReplicate3 17        ===>  [17, 17, 17]
        myReplicate 3 [1, 2]   ===>  [[1,2],[1,2],[1,2]]
        myReplicate 0 "help"   ===>  [ ]
          
    2. What is the formal type of the myReplicate function?
    3. One of the strong points of Haskell is that the language is strongly typed. How is it possible for the myReplicate function to allow any data type for the item parameter? Explain.
    4. What restrictions does Haskell enforce for myReplicate, regarding the size parameter? Experiment with real numbers, fractions, or integers for size, and indicate/explain what happens.
    5. How could you modify/expand the declaration of myReplicate, so that the item parameter had to be a String? (That is, the Haskell compiler would generate an error, if item was not a string.)
  4. Revise the previous replicate function, so that it is tail recursive with a separate replicateKernel function.

  5. Write a procedure that computes the termial of any natural number num, that is, the result of adding together all of the natural numbers up to and including num. Here are some illustrative sample calls:

      termial 7  ===> 28 -- = 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0
      termial 1  ===> 1  -- = 1 + 0
      termial 0  ===> 0
        
  6. Write a procedure double-each-element that takes a list of numbers and returns a list of their doubles:

    double-each-element [3 -62 41.4 17/4]  ===> [6 -124 82.8 17/2]
    double-each-element [0] ===> [0]
    double-each-element [ ] ===> [ ]
        
  7. Suppose lst1 and lst2 are two lists of numbers in ascending order. Write a function merge lst1 lst2 that returns a list that contains all of the items (including duplicates) from each of the original lists, so that the final list also has its elements in ascending order.

Extra Credit Problem

  1. Computing a Babysitter's Fee

    A baby sitter charges $2.75 per hour until 9:00 pm (while the kids are still up), $1.75 per hour between 9:00 pm and midnight, and $2.25 per hour after midnight (since late night baby sitting interferes with morning classes).

    Write a Haskell function that reads four integer values (the sitter's starting time in hours and minutes and the ending time in hours and minutes) and computes the sitter's fee. Assume all times are between 6:00 pm and 6:00 am, and hours should be specified as being between 0 and 12 (inclusive). Hours outside the range of 0 to 12 should be considered invalid.

    The following table may clarify allowed time values for this problem.

    Starting Starting Ending Ending StartingEnding
    Hour Minutes Hour Minutes Time time
    8 0 3 30 8:00pm 3:30am
    6 0 0 45 6:00pm 12:45am
    12 0 6 0 12:00am (midnight) 6:00am

    Programming Notes:


created 8 February 2020
revised 10, 20 February 2020
Valid HTML 4.01! Valid CSS!
For more information, please contact Henry M. Walker at walker@cs.grinnell.edu.