Add test 1
Squashed commit of the following: commit 82aa61982e9c65f65f221fbbcdb41fe8a21321ec Author: AKP <abi@tdpain.net> Date: Thu Nov 9 12:33:56 2023 +0000 Question 5 commit 7239dcaa65545c9a5b8b634213c813438c8e52f8 Author: AKP <abi@tdpain.net> Date: Thu Nov 9 11:47:10 2023 +0000 Question 4 commit 507520373221469ea2f71ee44b67f51dbf9a2455 Author: AKP <abi@tdpain.net> Date: Thu Nov 9 11:40:56 2023 +0000 Question 3 commit 7138150a9c7f34ceb4fdb9c10a018b9cd45cb196 Author: AKP <abi@tdpain.net> Date: Thu Nov 9 11:11:26 2023 +0000 Question 2 commit 808293dff53bd033ea9138ef01a4cb2dfab8fbca Author: AKP <abi@tdpain.net> Date: Thu Nov 9 11:05:24 2023 +0000 Question 1 commit 9f4b80f7e887c0b3665e95ef1be1678e116ec2bc Author: AKP <abi@tdpain.net> Date: Thu Nov 9 11:00:25 2023 +0000 Add base files
This commit is contained in:
parent
a938af47bb
commit
0262b34e47
4 changed files with 443 additions and 0 deletions
225
test1/README.md
Normal file
225
test1/README.md
Normal file
|
@ -0,0 +1,225 @@
|
|||
# Test 1
|
||||
|
||||
## Marking table
|
||||
|
||||
The exercises are defined so that it is hard to get a first-class mark.
|
||||
|
||||
| Mark | Cut-off |
|
||||
| ------------ | ------------------ |
|
||||
| 1st | 28 marks and above |
|
||||
| upper second | 24-27 marks |
|
||||
| lower second | 20-23 marks |
|
||||
| third | 16-19 marks |
|
||||
| fail | 0-15 marks |
|
||||
|
||||
All questions have equal weight, with eight marks each, with a total of 40
|
||||
marks.
|
||||
|
||||
## Preparation
|
||||
|
||||
* The test must be completed on JupyterLab.
|
||||
* Run `git pull` on JupyterLab to make sure you have the latest version of the
|
||||
course repository.
|
||||
* We have defined some helper functions for your in the `Types.hs` file. You are
|
||||
encouraged to make use of them in your solutions.
|
||||
* Do __not__ modify either the file `Types.hs` or the file
|
||||
`Test1-Template.hs`.
|
||||
* Copy the file `Test1-Template.hs` to a new file called
|
||||
`Test1.hs` and write your solutions in `Test1.hs`.
|
||||
|
||||
__Don't change the header of this file, including the module declaration, and,
|
||||
moreover, don't change the type signature of any of the given functions for
|
||||
you to complete.__
|
||||
|
||||
__If you do make changes, then we will not be able to mark your submission and
|
||||
hence it will receive zero marks!__
|
||||
* Solve the exercises below in the file `Test1.hs`.
|
||||
|
||||
## Submission procedure
|
||||
|
||||
* If your submission doesn't compile or fails to pass the presubmit script on
|
||||
JupyterLab, it will get zero marks.
|
||||
* Run the presubmit script provided to you on your submission from Jupyter by
|
||||
running `./presubmit.sh Test1` in the terminal (in the same folder as
|
||||
your submission).
|
||||
* This will check that your submission is in the correct format.
|
||||
* If it is, submit it on Canvas.
|
||||
* Otherwise fix and repeat the presubmission procedure.
|
||||
|
||||
## Plagiarism
|
||||
|
||||
Plagiarism will not be tolerated. Copying and contract cheating have led to full
|
||||
loss of marks, and even module or degree failure, in the past.
|
||||
|
||||
You will need to sign a declaration on Canvas, before submission, that you
|
||||
understand the [rules](/README.md#plagiarism) and are abiding by them, in order
|
||||
for your submission to qualify.
|
||||
|
||||
## Background material
|
||||
|
||||
- Each question has some **Background Material**, an **Implementation Task** and
|
||||
possibly some **Examples**.
|
||||
- Read this material first, then implement the requested function.
|
||||
- The corresponding type appears in the file `Test1-Template.hs` (to be
|
||||
copied by you).
|
||||
- Replace the default function implementation of `undefined` with your own
|
||||
function.
|
||||
|
||||
## More Rules
|
||||
|
||||
* This is an open book test.
|
||||
* You may consult your own notes, the course materials, any of the recommended
|
||||
books or [Hoogle](https://hoogle.haskell.org/).
|
||||
* Feel free to write helper functions whenever convenient.
|
||||
* All the exercises may be solved without importing additional modules. Do not
|
||||
import any modules, as it may interfere with the marking.
|
||||
|
||||
## Submission Deadline
|
||||
|
||||
* The official submission deadline is 1pm.
|
||||
* If you are provided extra time by the Welfare office then your submission
|
||||
deadline is 1:30pm or 2:00pm.
|
||||
* Submissions close 10 minutes after your deadline, and late submissions have 5%
|
||||
penalty
|
||||
|
||||
## Question 1 — Even majority (**8 marks**)
|
||||
|
||||
**Task** Write the following function `evenMajority`, that takes a list of
|
||||
integers, and tells whether more than half of them are even.
|
||||
|
||||
```haskell
|
||||
evenMajority :: [Int] -> Bool
|
||||
evenMajority ns = undefined
|
||||
```
|
||||
|
||||
## Question 2 — 5-smooth numbers (**8 marks**)
|
||||
|
||||
A 5-smooth number is an integer which has no prime factor larger than 5. For an
|
||||
integer N, we define S(N) as the set of 5-smooth numbers less than or equal to
|
||||
N. For example S(20) = {1,2,3,4,5,6,8,9,10,12,15,16,18,20}
|
||||
|
||||
**Task** Define the following function `get5SmoothNumbers`, that gives a list of
|
||||
all 5-smooth numbers less than or equal to a given number.
|
||||
|
||||
```haskell
|
||||
get5SmoothNumbers :: Int -> [Int]
|
||||
get5SmoothNumbers k = undefined
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
```hs
|
||||
*Test1> get5SmoothNumbers 25
|
||||
[1,2,3,4,5,6,8,9,10,12,15,16,18,20,24,25]
|
||||
|
||||
*Test1> get5SmoothNumbers 50
|
||||
[1,2,3,4,5,6,8,9,10,12,15,16,18,20,24,25,27,30,32,36,40,45,48,50]
|
||||
```
|
||||
|
||||
## Question 3 — Train stops (**8 marks**)
|
||||
|
||||
Consider the following type of train stops on the West Midlands Railway line,
|
||||
from Redditch to Birmingham New Street.
|
||||
|
||||
```haskell
|
||||
data TrainStop = BirminghamNewStreet
|
||||
| FiveWays
|
||||
| University
|
||||
| SellyOak
|
||||
| Bournville
|
||||
| KingsNorton
|
||||
| Northfield
|
||||
| Longbridge
|
||||
| BarntGreen
|
||||
| Alvechurch
|
||||
| Redditch
|
||||
deriving (Eq, Show)
|
||||
```
|
||||
|
||||
We define the function `theStopAfter` on this type, which encodes the
|
||||
information of which stop comes immediately after which stop.
|
||||
|
||||
```haskell
|
||||
theStopAfter :: TrainStop -> TrainStop
|
||||
theStopAfter Redditch = Alvechurch
|
||||
theStopAfter Alvechurch = BarntGreen
|
||||
theStopAfter BarntGreen = Longbridge
|
||||
theStopAfter Longbridge = Northfield
|
||||
theStopAfter Northfield = KingsNorton
|
||||
theStopAfter KingsNorton = Bournville
|
||||
theStopAfter Bournville = SellyOak
|
||||
theStopAfter SellyOak = University
|
||||
theStopAfter University = FiveWays
|
||||
theStopAfter FiveWays = BirminghamNewStreet
|
||||
theStopAfter BirminghamNewStreet = undefined
|
||||
```
|
||||
|
||||
Note that the function is undefined on `BirminghamNewStreet` because that is the
|
||||
last possible stop on this line. You should ensure that this function is never
|
||||
called on `BirminghamNewStreet`, because the program will crash if you do that.
|
||||
|
||||
**Task** Define the following function `comesBefore`, using the given
|
||||
`theStopAfter` function, such that `comesBefore s1 s2` is `True` if and only if
|
||||
`s1` is a stop preceding stop `s2`.
|
||||
|
||||
```haskell
|
||||
comesBefore :: TrainStop -> TrainStop -> Bool
|
||||
comesBefore s1 s2 = undefined
|
||||
```
|
||||
|
||||
Some examples:
|
||||
|
||||
```hs
|
||||
*Test1> comesBefore University BirminghamNewStreet
|
||||
True
|
||||
*Test1> comesBefore Bournville FiveWays
|
||||
True
|
||||
*Test1> comesBefore BirminghamNewStreet University
|
||||
False
|
||||
*Test1> comesBefore University KingsNorton
|
||||
False
|
||||
*Test1> comesBefore University University
|
||||
False
|
||||
```
|
||||
|
||||
## Question 4 — Repeated applications of a function (**8 marks**)
|
||||
|
||||
**Task** Write a function `countApplications`
|
||||
|
||||
```haskell
|
||||
countApplications :: (a -> a) -> (a -> Bool) -> a -> Int
|
||||
countApplications f p x = undefined
|
||||
```
|
||||
|
||||
that takes
|
||||
|
||||
1. a function `f :: a -> a`,
|
||||
1. a termination condition `p :: a -> Bool`, and
|
||||
1. an input `x :: a`,
|
||||
|
||||
and counts the number of times that the function `f` must be repeatedly applied
|
||||
to `x` until the output satisfies the condition `p`.
|
||||
|
||||
Here is an example of how to use this function:
|
||||
|
||||
```hs
|
||||
*Test1> countApplications (\n -> n `div` 2) odd 8
|
||||
3
|
||||
*Test1> countApplications (\n -> n `div` 2) odd 10
|
||||
1
|
||||
```
|
||||
|
||||
We will only test your implementation of `countApplications` on functions that
|
||||
do terminate with respect to the termination condition.
|
||||
|
||||
## Question 5 — Higher order functions (**8 marks**)
|
||||
|
||||
**Task** Write a function `f` of the following type
|
||||
|
||||
```haskell
|
||||
f :: (a -> a -> r) -> ((a -> r) -> a) -> r
|
||||
f g h = undefined
|
||||
```
|
||||
|
||||
The function should terminate for all terminating inputs. Your solution should
|
||||
not use recursion or `undefined`.
|
59
test1/Test1.hs
Normal file
59
test1/Test1.hs
Normal file
|
@ -0,0 +1,59 @@
|
|||
-- setting the "warn-incomplete-patterns" flag asks GHC to warn you
|
||||
-- about possible missing cases in pattern-matching definitions
|
||||
{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
|
||||
|
||||
-- see https://wiki.haskell.org/Safe_Haskell
|
||||
{-# LANGUAGE Safe #-}
|
||||
|
||||
module Test1 ( evenMajority
|
||||
, get5SmoothNumbers
|
||||
, comesBefore
|
||||
, countApplications
|
||||
, f
|
||||
) where
|
||||
|
||||
import Types
|
||||
|
||||
{- QUESTION 1 -}
|
||||
|
||||
_countEvens :: [Int] -> Int
|
||||
_countEvens ns = foldl (\acc x -> if even x then acc + 1 else acc) 0 ns
|
||||
|
||||
evenMajority :: [Int] -> Bool
|
||||
evenMajority ns = let half = (length ns) `div` 2 in (_countEvens ns) > half
|
||||
|
||||
{- QUESTION 2 -}
|
||||
|
||||
_is5Smooth :: Int -> Bool
|
||||
_is5Smooth n = foldl (\acc x -> acc && x <= 5) True (primeFactors n)
|
||||
|
||||
get5SmoothNumbers :: Int -> [Int]
|
||||
get5SmoothNumbers n = filter _is5Smooth [1..n]
|
||||
|
||||
{- QUESTION 3 -}
|
||||
|
||||
_getStationsBefore :: TrainStop -> Maybe TrainStop -> [TrainStop]
|
||||
_getStationsBefore finalStop Nothing = _getStationsBefore finalStop (Just Redditch)
|
||||
_getStationsBefore finalStop (Just previousStop) | finalStop == previousStop = []
|
||||
| otherwise = previousStop:(_getStationsBefore finalStop (Just (theStopAfter previousStop)))
|
||||
|
||||
comesBefore :: TrainStop -> TrainStop -> Bool
|
||||
comesBefore s1 s2 = not (foldl (\acc x -> acc && x /= s1) True (_getStationsBefore s2 Nothing))
|
||||
|
||||
{- QUESTION 4 -}
|
||||
|
||||
_countApplications :: (a -> a) -> (a -> Bool) -> a -> Int -> Int
|
||||
_countApplications f p acc tries | (p acc) = tries
|
||||
| otherwise = _countApplications f p (f acc) (tries + 1)
|
||||
|
||||
countApplications :: (a -> a) -> (a -> Bool) -> a -> Int
|
||||
countApplications f p x = _countApplications f p x 0
|
||||
|
||||
{- QUESTION 5 -}
|
||||
|
||||
_cloneArgument :: (a -> a -> r) -> (a -> r)
|
||||
_cloneArgument f = (\x -> f x x)
|
||||
|
||||
f :: (a -> a -> r) -> ((a -> r) -> a) -> r
|
||||
f g h = let i = (_cloneArgument g) in
|
||||
g (h i) (h i)
|
56
test1/Types.hs
Normal file
56
test1/Types.hs
Normal file
|
@ -0,0 +1,56 @@
|
|||
-- setting the "warn-incomplete-patterns" flag asks GHC to warn you
|
||||
-- about possible missing cases in pattern-matching definitions
|
||||
{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
|
||||
|
||||
-- see https://wiki.haskell.org/Safe_Haskell
|
||||
{-# LANGUAGE Safe #-}
|
||||
|
||||
---------------------------------------------------------------------------------
|
||||
-------------------------- DO **NOT** MODIFY THIS FILE --------------------------
|
||||
---------------------------------------------------------------------------------
|
||||
|
||||
module Types where
|
||||
|
||||
-- Question 2
|
||||
|
||||
factors :: Int -> [Int]
|
||||
factors n = [ k | k <- [1..n] , n `mod` k == 0 ]
|
||||
|
||||
isPrime :: Int -> Bool
|
||||
isPrime n = factors n == [1, n]
|
||||
|
||||
primeFactors :: Int -> [Int]
|
||||
primeFactors n = [x | x <- [1..n], n `mod` x == 0 && isPrime x]
|
||||
|
||||
-- Question 3
|
||||
|
||||
data TrainStop = BirminghamNewStreet
|
||||
| FiveWays
|
||||
| University
|
||||
| SellyOak
|
||||
| Bournville
|
||||
| KingsNorton
|
||||
| Northfield
|
||||
| Longbridge
|
||||
| BarntGreen
|
||||
| Alvechurch
|
||||
| Redditch
|
||||
deriving (Eq, Show)
|
||||
|
||||
theStopAfter :: TrainStop -> TrainStop
|
||||
theStopAfter Redditch = Alvechurch
|
||||
theStopAfter Alvechurch = BarntGreen
|
||||
theStopAfter BarntGreen = Longbridge
|
||||
theStopAfter Longbridge = Northfield
|
||||
theStopAfter Northfield = KingsNorton
|
||||
theStopAfter KingsNorton = Bournville
|
||||
theStopAfter Bournville = SellyOak
|
||||
theStopAfter SellyOak = University
|
||||
theStopAfter University = FiveWays
|
||||
theStopAfter FiveWays = BirminghamNewStreet
|
||||
theStopAfter BirminghamNewStreet = undefined
|
||||
|
||||
-- Question 4
|
||||
|
||||
divideBy2 :: Int -> Int
|
||||
divideBy2 n = n `div` 2
|
103
test1/presubmit.sh
Normal file
103
test1/presubmit.sh
Normal file
|
@ -0,0 +1,103 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ "$1" = "" ]
|
||||
then
|
||||
echo "You forgot to add the assignment name, e.g. 'Assessed1'."
|
||||
echo "Please run the script again with the right argument."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ -f "$1.hs" ]
|
||||
then
|
||||
echo "File '$1.hs' not found."
|
||||
echo "Are you in the correct directory?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Trying to compile your submission..."
|
||||
|
||||
# Create temporary directory
|
||||
temp_dir=$(mktemp -d)
|
||||
|
||||
ghc $1.hs -odir $temp_dir -hidir $temp_dir
|
||||
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo ""
|
||||
echo "Your file '$1.hs' did not compile."
|
||||
echo "Please fix it before submitting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ -f "$temp_dir/$1.o" ]
|
||||
then
|
||||
echo ""
|
||||
echo "The module name in '$1.hs' does match not the filename '$1'."
|
||||
echo "Please make sure you that"
|
||||
echo -e "\t(i) your file is called something like 'TestX.hs'"
|
||||
echo -e "\t(ii) you did not change the top of the template"
|
||||
echo "and try again."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ghc -XSafe $1.hs -odir $temp_dir -hidir $temp_dir
|
||||
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo ""
|
||||
echo "Your file did not compile with '-XSafe.'"
|
||||
echo "Did you remove '{-# LANGUAGE Safe #-}' from the template?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create file for ensuring type signatures have not been modified
|
||||
|
||||
cat >> $temp_dir/Signatures.hs << 'END'
|
||||
{-# LANGUAGE Safe #-}
|
||||
module Signatures where
|
||||
|
||||
import Types
|
||||
import Test1
|
||||
|
||||
{- QUESTION 1 -}
|
||||
|
||||
evenMajorityTest :: [Int] -> Bool
|
||||
evenMajorityTest = evenMajority
|
||||
|
||||
{- QUESTION 2 -}
|
||||
|
||||
get5SmoothNumbersTest :: Int -> [Int]
|
||||
get5SmoothNumbersTest = get5SmoothNumbers
|
||||
|
||||
{- QUESTION 3 -}
|
||||
|
||||
comesBeforeTest :: TrainStop -> TrainStop -> Bool
|
||||
comesBeforeTest = comesBefore
|
||||
|
||||
{- QUESTION 4 -}
|
||||
|
||||
countApplicationsTest :: (a -> a) -> (a -> Bool) -> a -> Int
|
||||
countApplicationsTest = countApplications
|
||||
|
||||
{- QUESTION 5 -}
|
||||
|
||||
fTest :: (a -> a -> r) -> ((a -> r) -> a) -> r
|
||||
fTest = f
|
||||
END
|
||||
|
||||
ghc -XSafe $temp_dir/Signatures.hs -odir $temp_dir -hidir $temp_dir
|
||||
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo ""
|
||||
echo "Your file did not compile with the correct type signatures."
|
||||
echo "Did you modify the type signatures from the template?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "All checks passed."
|
||||
echo "You are ready to submit!"
|
||||
|
||||
# Cleanup temporary directory
|
||||
rm -r $temp_dir
|
Reference in a new issue