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 Int
s 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 indeleteBST x t
,- for all
y
int
, ify /= x
, theny
appears indeleteBST y t
.
You are, as always, free to introduce any helper functions you might need.
deleteBST :: Int -> IntTree -> IntTree
deleteBST = undefined