Homework 1

Haskell training, part I

This homework is written in literate Haskell; you can download the raw source to fill in yourself. You’re welcome to submit literate Haskell yourself, or to start fresh in a new file, literate or not.

Please submit homeworks via the DCI submission page.

Let’s learn some Haskell! We’ll be going over some rudiments in class, and there’s excellent documentation online.

In most places where I’d like you to fill in a definition, I’ve used the convenient Haskell term undefined, which let’s you compile an incomplete program. (Running undefined parts of your program is an error, and your program will crash.)

Please leave the following line in. (If you take it out, the grader will reject your program.) We’ll talk more about Haskell’s module system later in the semester.

module Hw01 where

You can test this program by running ghci on it. If you edit your code, you can use the :reload command to load in your new definitions.

If your program has type errors, it won’t compile.

Problem 1: natural recursion

Please don’t use any Prelude functions to implement these—just write natural recursion, like we did in class.

Write a function called sumUp that sums a list of numbers.

sumUp :: [Int] -> Int
sumUp []     = undefined
sumUp (x:xs) = undefined

Write a function called evens that selects out the even numbers from a list. For example, evens [1,2,3,4,5] should yield [2,4]. You can use the library function even.

evens :: [Int] -> [Int]
evens []     = undefined
evens (x:xs) = undefined

Write a function called incAll that increments a list of numbers by one. You’ll have to fill in the arguments and write the cases yourself.

incAll :: [Int] -> [Int]
incAll = undefined

Now write a function called incBy that takes a number and increments a list of numbers by that number.

incBy :: Int -> [Int] -> [Int]
incBy = undefined

Write a function append that takes two lists and appends them. For example, append [1,2] [3,4] == [1,2,3,4]. (This function is called (++) in the standard library… but don’t use that to define your version!)

append :: [Int] -> [Int] -> [Int]
append = undefined

Problem 2: data types

Haskell (and functional programming in general) is centered around datatype definitions. Here’s a definition for a simple tree:

data IntTree = Empty | Node IntTree Int IntTree deriving (Eq,Show)

Write a function isLeaf that determines whether a given node is a leaf, i.e., both its children are Empty.

isLeaf :: IntTree -> Bool
isLeaf Empty = undefined
isLeaf (Node l x r) = undefined

Write a function sumTree that sums up all of the values in an IntTree.

sumTree :: IntTree -> Int
sumTree = undefined

Write a function fringe that yields the fringe of the tree from left to right, i.e., the list of values in the leaves of the tree, reading left to right.

For example, the fringe of Node (Node Empty 1 (Node Empty 2 Empty)) 5 (Node (Node Empty 7 Empty) 10 Empty) is [2,7].

fringe :: IntTree -> [Int]
fringe = undefined

Problem 3: insertion sort

Write a function insertionSort that takes a list of Ints and produces one in sorted order. Use the insertion sort algorithm. You might want to write a helper function.

insertionSort :: [Int] -> [Int]
insertionSort = undefined

Problem 4: binary search trees

Write a function isBST to determine whether or not a given tree is a strict binary search tree, i.e., the tree is either empty, or it is node such that:

  • all values in the left branch are less than the value of the node, and
  • all values in the right branch are greater than the value of the node.

I’ve given you a helper function maybeBounded that checks whether a given Int is bounded. It uses the Haskell Maybe type, which is essentially defined as:

data Maybe Int = Nothing | Just Int

Maybe makes a type nullable. In Java, every non-primitive type is nullable—the null object can have any class. In Haskell, you must explicitly ask for nullability, and nullness and non-nullness are both explicit: Nothing is null, and the non-null Just x holds a value x. We’ll look at this more deeply in the next assignment, when we talk about datatypes.

maybeBounded :: Maybe Int -> Maybe Int -> Int -> Bool
maybeBounded Nothing Nothing x = True
maybeBounded Nothing (Just upper) x = x < upper
maybeBounded (Just lower) Nothing x = lower < x
maybeBounded (Just lower) (Just upper) x = lower < x && x < upper
isBST :: IntTree -> Bool
isBST = undefined

Write a function insertBST that performs BST insert. You may assume your input is a BST.

insertBST :: Int -> IntTree -> IntTree
insertBST = undefined

Write a function deleteBST that removes a given value from a BST. You may assume your input is a BST. Feel free to look up the algorithm… I had to!

It doesn’t really matter which algorithm you use, so long as the function works correctly, i.e., for all BSTs t:

  • deleteBST x t is a BST,
  • x doesn’t appear in deleteBST x t,
  • for all y in t, if y /= x, then y appears in deleteBST y t.

You are, as always, free to introduce any helper functions you might need.

deleteBST :: Int -> IntTree -> IntTree
deleteBST = undefined