https://github.com/plsyssec/00-warmup
Homework Assignment #0
https://github.com/plsyssec/00-warmup
Last synced: about 1 month ago
JSON representation
Homework Assignment #0
- Host: GitHub
- URL: https://github.com/plsyssec/00-warmup
- Owner: PLSysSec
- License: mit
- Created: 2017-01-27T01:02:08.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2016-09-28T20:49:12.000Z (over 9 years ago)
- Last Synced: 2025-03-02T01:44:10.062Z (over 1 year ago)
- Language: Haskell
- Size: 16.6 KB
- Stars: 0
- Watchers: 12
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
---
title: HW 0, due 9/30/2016
headerImg: angles.jpg
---
## Download
```bash
$ git clone https://github.com/ucsd-cse131/00-warmup.git
$ cd 00-warmup/
```
## Overview
This is a _warm up_ assignment which will
* refresh your memory of functional programming from CSE 130, and
* provide a quick introduction to Haskell.
To this end, you will, reimplement certain problems from
CSE 130 in Haskell. Recall that the problems require
relatively little code ranging from 2 to 15 lines.
If any function requires more than that, you can be
sure that you need to rethink your solution.
1. [lib/Hw0.hs](/lib/Hw0.hs) has skeleton functions with
missing bodies that you will fill in,
2. [tests/Test.hs](/tests/Test.hs) has some sample tests,
and testing code that you will use to check your
assignments before submitting.
You should only need to modify the parts of the files which say:
```haskell
error "TBD: ..."
```
with suitable Haskell implementations.
**Note:** Start early, to avoid any unexpected shocks late in the day.
## Assignment Testing and Evaluation
Your functions/programs **must** compile and run on `ieng6.ucsd.edu`.
Most of the points, will be awarded automatically, by
**evaluating your functions against a given test suite**.
[Tests.hs](/tests/Test.hs) contains a very small suite
of tests which gives you a flavor of of these tests.
When you run
```shell
$ stack test
```
Your last lines should have
```
All N tests passed (...)
OVERALL SCORE = ... / ...
```
**or**
```
K out of N tests failed
OVERALL SCORE = ... / ...
```
**If your output does not have one of the above your code will receive a zero**
If for some problem, you cannot get the code to compile,
leave it as is with the `error ...` with your partial
solution enclosed below as a comment.
The other lines will give you a readout for each test.
You are encouraged to try to understand the testing code,
but you will not be graded on this.
## Submission Instructions
To submit your code, just do:
```bash
$ make turnin
```
`turnin` will provide you with a confirmation of the
submission process; make sure that the size of the file
indicated by `turnin` matches the size of your file.
See the ACS Web page on [turnin](http://acs.ucsd.edu/info/turnin.php)
for more information on the operation of the program.
## Problem 1: [Roots and Persistence](http://mathworld.wolfram.com/AdditivePersistence.html)
### (a) 10 points
Fill in the implementation of
```haskell
sumList :: [Int] -> Int
sumList xs = error "TBD:sumList"
```
that such that `sumList xs` returns the sum of the integer elements of
`xs`. Once you have implemented the function, you should get the following
behavior at the prompt:
```haskell
ghci> sumList [1, 2, 3, 4]
10
ghci> sumList [1, -2, 3, 5]
7
ghci> sumList [1, 3, 5, 7, 9, 11]
36
```
## (b) 10 points
Fill in the implementation of the function
```haskell
digitsOfInt :: Int -> [Int]
digitsOfInt n = error "TBD:digitsOfInt"
```
such that `digitsOfInt n`
* returns `[]` if `n` is not positive, and otherwise
* returns the list of digits of `n` in the order in which they appear in `n`.
Once you have implemented the function, you should get the following:
```haskell
ghci> digitsOfInt 3124
[3, 1, 2, 4]
ghci> digitsOfInt 352663
[3, 5, 2, 6, 6, 3]
```
### (c) 10+10 points
Consider the process of taking a number, adding its digits,
then adding the digits of the number derived from it, etc.,
until the remaining number has only one digit.
The number of additions required to obtain a single digit
from a number `n` is called the *additive persistence* of `n`,
and the digit obtained is called the *digital root* of `n`.
For example, the sequence obtained from the starting number
`9876` is `9876`, `30`, `3`, so `9876` has an additive
persistence of `2` and a digital root of `3`.
Write two functions
```haskell
additivePersistence :: Int -> Int
additivePersistence n = error "TBD:additivePersistence"
digitalRoot :: Int -> Int
digitalRoot n = error "TBD:digitalRoot"
```
that take positive integer arguments `n` and return respectively
the additive persistence and the digital root of `n`. Once you
have implemented the functions, you should get the following
behavior at the prompt:
```haskell
ghci> additivePersistence 9876
2
ghci> digitalRoot 9876
3
```
## Problem 2: Palindromes
### (a) 15 points
Without using any built-in functions (e.g. `reverse`),
write an function:
```haskell
listReverse :: [a] -> [a]
listReverse xs = error "TBD:listReverse"
```
such that `listReverse [x1,x2,...,xn]` returns the list `[xn,...,x2,x1]`
i.e. the input list but with the values in reversed order.
You should get the following behavior:
```haskell
ghci> listReverse [1, 2, 3, 4]
[4, 3, 2, 1]
ghci> listReverse ["a", "b", "c", "d"]
["d", "c", "b", "a"]
```
###(b) 10 points
A *palindrome* is a word that reads the same from left-to-right and
right-to-left. Write a function
```haskell
palindrome :: String -> Bool
palindrome w = error "TBD:palindrome"
```
such that `palindrome w` returns `True` if the string is a palindrome and
`False` otherwise. You should get the following behavior:
```haskell
ghci> palindrome "malayalam"
True
ghci> palindrome "myxomatosis"
False
```
## Problem 3: Folding Warm-Up
### (a) 15 points
Fill in the skeleton given for `sqsum`,
which uses `foldl'` (the equivalent of Ocaml's `List.fold_left`)
to get a function
```haskell
sqSum :: [Int] -> Int
```
such that `sqSum [x1,...,xn]` returns the integer `x1^2 + ... + xn^2`
Your task is to fill in the appropriate values for
1. the folding function `f` and
2. the base case `base`.
Once you have implemented the function, you should get
the following behavior:
```haskell
ghci> sqSum []
0
ghci> sqSum [1, 2, 3, 4]
30
ghci> sqSum [(-1), (-2), (-3), (-4)]
30
```
### (b) 30 points
Fill in the skeleton given for `pipe` which uses `foldl'`
to get a function
```haskell
pipe :: [(a -> a)] -> (a -> a)
```
such that `pipe [f1,...,fn] x` (where `f1,...,fn` are functions!)
should return `f1(f2(...(fn x)))`.
Again, your task is to fill in the appropriate values for
1. the folding function `f` and
2. the base case `base`.
Once you have implemented the function, you should get
the following behavior:
```haskell
ghci> pipe [] 3
3
ghci> pipe [(\x -> x+x), (\x -> x + 3)] 3
12
ghci> pipe [(\x -> x * 4), (\x -> x + x)] 3
24
```
### (c) 20 points
Fill in the skeleton given for `sepConcat`,
which uses `foldl'` to get a function
```haskell
sepConcat :: String -> [String] -> String
```
Intuitively, the call `sepConcat sep [s1,...,sn]` where
* `sep` is a string to be used as a separator, and
* `[s1,...,sn]` is a list of strings
should behave as follows:
* `sepConcat sep []` should return the empty string `""`,
* `sepConcat sep [s]` should return just the string `s`,
* otherwise (if there is more than one string) the output
should be the string `s1 ++ sep ++ s2 ++ ... ++ sep ++ sn`.
You should only modify the parts of the skeleton consisting
of `error "TBD" "`. You will need to define the function `f`,
and give values for `base` and `l`.
Once done, you should get the following behavior:
```haskell
ghci> sepConcat ", " ["foo", "bar", "baz"]
"foo, bar, baz"
ghci> sepConcat "---" []
""
ghci> sepConcat "" ["a", "b", "c", "d", "e"]
"abcde"
ghci> sepConcat "X" ["hello"]
"hello"
```
### (d) 10 points
Implement the function
```haskell
stringOfList :: (a -> String) -> [a] -> String
```
such that `stringOfList f [x1,...,xn]` should return the string
`"[" ++ (f x1) ++ ", " ++ ... ++ (f xn) ++ "]"`
This function can be implemented on one line,
**without using any recursion** by calling
`map` and `sepConcat` with appropriate inputs.
You should get the following behavior:
```haskell
ghci> stringOfList show [1, 2, 3, 4, 5, 6]
"[1, 2, 3, 4, 5, 6]"
ghci> stringOfList (fun x -> x) ["foo"]
"[foo]"
ghci> stringOfList (stringOfList show) [[1, 2, 3], [4, 5], [6], []]
"[[1, 2, 3], [4, 5], [6], []]"
```
## Problem 4: Big Numbers
The Haskell type `Int` only contains values up to a certain size (for reasons
that will become clear as we implement our own compiler). For example,
```haskell
ghci> let x = 99999999999999999999999999999999999999999999999 :: Int
:3:9: Warning:
Literal 99999999999999999999999999999999999999999999999 is out of the Int range -9223372036854775808..9223372036854775807
```
You will now implement functions to manipulate arbitrarily large
numbers represented as `[Int]`, i.e. lists of `Int`.
### (a) 10 + 5 + 10 points
Write a function
```haskell
clone :: a -> Int -> [a]
```
such that `clone x n` returns a list of `n` copies of the value `x`.
If the integer `n` is `0` or negative, then `clone` should return
the empty list. You should get the following behavior:
```haskell
ghci> clone 3 5
[3, 3, 3, 3, 3]
ghci> clone "foo" 2
["foo", "foo"]
```
Use `clone` to write a function
```haskell
padZero :: [Int] -> [Int] -> ([Int], [Int])
```
which takes two lists: `[x1,...,xn]` `[y1,...,ym]` and
adds zeros in front of the _shorter_ list to make the
lists equal.
Your implementation should *not** be recursive.
You should get the following behavior:
```haskell
ghci> padZero [9, 9] [1, 0, 0, 2]
([0, 0, 9, 9], [1, 0, 0, 2])
ghci> padZero [1, 0, 0, 2] [9, 9]
([1, 0, 0, 2], [0, 0, 9, 9])
```
Next, write a function
```haskell
removeZero :: [Int] -> [Int]
```
that takes a list and removes a prefix of leading zeros, yielding
the following behavior:
```haskell
ghci> removeZero [0, 0, 0, 1, 0, 0, 2]
[1, 0, 0, 2]
ghci> removeZero [9, 9]
[9, 9]
ghci> removeZero [0, 0, 0, 0]
[]
```
### (b) 25 points
Let us use the list `[d1, d2, ..., dn]`, where each `di`
is between `0` and `9`, to represent the (positive)
**big-integer** `d1d2...dn`.
```haskell
type BigInt = [Int]
```
For example, `[9, 9, 9, 9, 9, 9, 9, 9, 9, 8]` represents
the big-integer `9999999998`. Fill out the implementation for
```haskell
bigAdd :: BigInt -> BigInt -> BigInt
```
so that it takes two integer lists, where each integer is
between `0` and `9` and returns the list corresponding to
the addition of the two big-integers. Again, you have to
fill in the implementation to supply the appropriate values
to `f`, `base`, `args`. You should get the following behavior:
```haskell
ghci> bigAdd [9, 9] [1, 0, 0, 2]
[1, 1, 0, 1]
ghci> bigAdd [9, 9, 9, 9] [9, 9, 9]
[1, 0, 9, 9, 8]
```
### (c) 15 + 20 points
Next you will write functions to multiply two big integers.
First write a function
```haskell
mulByDigit :: Int -> BigInt -> BigInt
```
which takes an integer digit and a big integer, and returns the
big integer list which is the result of multiplying the big
integer with the digit. You should get the following behavior:
```haskell
ghci> mulByDigit 9 [9,9,9,9]
[8,9,9,9,1]
```
Now, using `mulByDigit`, fill in the implementation of
```haskell
bigMul :: BigInt -> BigInt -> BigInt
```
Again, you have to fill in implementations for `f` , `base` , `args` only.
Once you are done, you should get the following behavior at the prompt:
```haskell
ghci> bigMul [9,9,9,9] [9,9,9,9]
[9,9,9,8,0,0,0,1]
ghci> bigMul [9,9,9,9,9] [9,9,9,9,9]
[9,9,9,9,8,0,0,0,0,1]
```