add Set2, Set3a, Set3b

This commit is contained in:
Joel Kaasinen
2020-05-06 09:13:03 +03:00
parent 5a850a2360
commit 748898b4ae
6 changed files with 944 additions and 0 deletions
+141
View File
@@ -0,0 +1,141 @@
-- Exercise set 2:
-- * Guards
-- * Lists
-- * Maybe
-- * Either
--
-- Functions you will need:
-- * head, tail
-- * take, drop
-- * length
-- * null
module Set2 where
import Mooc.Todo
-- Some imports you'll need. Don't add other imports :)
import Data.List
------------------------------------------------------------------------------
-- Ex 1: Define the constant years, that is a list of the values 1982,
-- 2004 and 2020 in this order.
years = todo
------------------------------------------------------------------------------
-- Ex 2: define the function takeFinal, which returns the n last
-- elements of the given list.
--
-- If the list is shorter than n, return all elements.
--
-- Hint! remember the take and drop functions.
takeFinal :: Int -> [a] -> [a]
takeFinal n xs = todo
------------------------------------------------------------------------------
-- Ex 3: Update an element at a certain index in a list. More
-- precisely, return a list that is identical to the given list except
-- the element at index i is x.
--
-- Note! indexing starts from 0
--
-- Examples:
-- updateAt 0 4 [1,2,3] ==> [4,2,3]
-- updateAt 2 0 [4,5,6,7] ==> [4,5,0,7]
updateAt :: Int -> a -> [a] -> [a]
updateAt i x xs = todo
------------------------------------------------------------------------------
-- Ex 4: substring i j s should return the substring of s starting at
-- index i and ending at index j.
--
-- Remember that strings are lists!
substring :: Int -> Int -> String -> String
substring i j s = todo
------------------------------------------------------------------------------
-- Ex 5: implement the function palindromify that chops a character
-- off the front _and_ back of a string until the result is a
-- palindrome.
--
-- Examples:
-- palindromify "ab" ==> ""
-- palindromify "aaay" ==> "aa"
-- palindromify "xabbay" ==> "abba"
-- palindromify "abracacabra" ==> "acaca"
palindromify :: String -> String
palindromify s = todo
------------------------------------------------------------------------------
-- Ex 6: implement safe integer devision, that is, a function that
-- returns a Just result normally, but Nothing if the divisor is zero.
--
-- Remember that integer division can be done with the div function.
--
-- Examples:
-- safeDiv 4 2 ==> Just 2
-- safeDiv 4 0 ==> Nothing
safeDiv :: Integer -> Integer -> Maybe Integer
safeDiv x y = todo
------------------------------------------------------------------------------
-- Ex 7: implement a function greet that greets a person given a first
-- name and possibly a last name. The last name is represented as a
-- Maybe String value.
--
-- Examples:
-- greet "John" Nothing ==> "Hello, John!"
-- greet "John" (Just "Smith") ==> "Hello, John Smith!"
greet :: String -> Maybe String -> String
greet first last = todo
------------------------------------------------------------------------------
-- Ex 8: safe list indexing. Define a function safeIndex so that
-- safeIndex xs i
-- gets the element at index i in the list xs. If i is not a valid
-- index, Nothing is returned.
--
-- Examples:
-- safeIndex [True] 1 ==> Nothing
-- safeIndex [10,20,30] 0 ==> Just 10
-- safeIndex [10,20,30] 2 ==> Just 30
-- safeIndex [10,20,30] 3 ==> Nothing
-- safeIndex ["a","b","c"] (-1) ==> Nothing
safeIndex :: [a] -> Int -> Maybe a
safeIndex xs i = todo
------------------------------------------------------------------------------
-- Ex 9: another variant of safe division. This time you should use
-- Either to return a string error message.
--
-- Examples:
-- eitherDiv 4 2 ==> Right 2
-- eitherDiv 4 0 ==> Left "4/0"
eitherDiv :: Integer -> Integer -> Either String Integer
eitherDiv x y = todo
------------------------------------------------------------------------------
-- Ex 10: implement the function addEithers, which combines two values of type
-- Either String Int into one like this:
--
-- - If both inputs were Ints, sum the Ints
-- - Otherwise, return the first argument that was not an Int
--
-- Exmaples:
--
-- addEithers (Right 1) (Right 2) ==> Right 3
-- addEithers (Right 1) (Left "fail") ==> Left "fail"
-- addEithers (Left "boom") (Left "fail") ==> Left "boom"
addEithers :: Either String Int -> Either String Int -> Either String Int
addEithers a b = todo
+115
View File
@@ -0,0 +1,115 @@
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
module Set2Test where
import Data.Char
import Data.List
import Test.QuickCheck
import Mooc.Th
import Mooc.Test
import Set2
main = score tests
tests = [(1,"years",[ex1_years])
,(2,"takeFinal",[ex2_takeFinal_1, ex2_takeFinal_2])
,(3,"updateAt",[ex3_updateAt])
,(4,"substring",[ex4_substring])
,(5,"palindromify",[ex5_palindromify])
,(6,"safeDiv",[ex6_safeDiv_zero, ex6_safeDiv_nonZero])
,(7,"greet",[ex7_greet_nothing, ex7_greet_just])
,(8,"safeIndex",[ex8_safeIndex_ok, ex8_safeIndex_fail])
,(9,"eitherDiv",[ex9_eitherDiv_zero, ex9_eitherDiv_nonZero])
,(10,"addEithers",[ex10_addEithers_both, ex10_addEithers_one, ex10_addEithers_neither])
]
-- -- -- -- -- --
ex1_years =
let origLength = length in
let length = origLength :: [a] -> Int in
conjoin [$(testing' [|length years|]) (?== 3)
,$(testing' [|head years|]) (?== 1982)
,$(testing' [|years !! 1|]) (?== 2004)
,$(testing' [|last years|]) (?== 2020)]
letter = choose ('a','z')
word = listOf1 letter
ex2_takeFinal_1 = property $ do
n <- choose (0,20)
k <- choose (0,n)
return $ $(testing [|takeFinal k [0..n]|]) (?== [n-k+1..n])
ex2_takeFinal_2 = property $ do
n <- choose (0,20)
k <- choose (0,n)
let inp = reverse [0..n]
return $ $(testing [|takeFinal k inp|]) (?== reverse [0..k-1])
ex3_updateAt = property $ do
ws <- listOf1 word
i <- choose (0,length ws - 1)
j <- choose (0,length ws - 1)
w <- word
return . $(testing [|updateAt i w ws|]) $ \v ->
conjoin [counterexample ("index "++show i) $ v!!i ?== w
,counterexample ("index "++show j) $ i/=j ==> v!!j ?== ws!!j]
ex4_substring = forAll_ $ \(prefix :: String, target, suffix) ->
$(testing [|substring (length prefix) (length prefix + length target) (prefix ++ target ++ suffix)|]) (?==target)
ex5_palindromify = property $ do
beef <- word
center <- sublistOf "z"
bun <- fmap nub word `suchThat` \w -> length w > 1
let answer = beef ++ center ++ reverse beef
input = bun ++ answer ++ bun
return $ $(testing [|palindromify input|]) (?== answer)
ex6_safeDiv_zero = forAll_ $ \x ->
$(testing [|safeDiv x 0|]) (?== Nothing)
ex6_safeDiv_nonZero = forAll_ $ \(x,y) ->
(y/=0) ==> $(testing [|safeDiv x y|]) (?== Just (div x y))
ex7_greet_nothing = forAllBlind word $ \first ->
$(testing [|greet first (Nothing :: Maybe String)|]) (?==("Hello, "++first++"!"))
ex7_greet_just = forAllBlind word $ \first ->
forAllBlind word $ \last ->
$(testing [|greet first (Just last)|]) (?==("Hello, "++first++" "++last++"!"))
ex8_safeIndex_ok = property $ do
ws <- listOf1 word
i <- choose (0,length ws - 1)
return $ $(testing [|safeIndex ws i|]) (?==Just (ws!!i))
ex8_safeIndex_fail = property $ do
is <- listOf1 (choose (10,20::Int))
i <- choose (0,10)
let neg = negate i - 1
let over = length is + i
return $ conjoin [$(testing [|safeIndex is neg|]) (?==Nothing)
,$(testing [|safeIndex is over|]) (?==Nothing)]
ex9_eitherDiv_zero = forAll_ $ \x ->
$(testing [|eitherDiv x 0|]) (?== Left (show x++"/0"))
ex9_eitherDiv_nonZero = forAll_ $ \(x,y) ->
(y/=0) ==> $(testing [|eitherDiv x y|]) (?== Right (div x y))
ex10_addEithers_both = forAll_ $ \(x,y) ->
$(testing [|addEithers (Right x :: Either String Int) (Right y :: Either String Int)|]) (?== Right (x+y))
ex10_addEithers_one = property $ do
err <- fmap Left arbitrary
int <- fmap Right arbitrary
~[x,y] <- shuffle [err,int]
return $ $(testing [|addEithers x y|]) (?==err)
ex10_addEithers_neither = forAll_ $ \(a,b) ->
$(testing [|addEithers (Left a :: Either String Int) (Left b :: Either String Int)|]) (?==Left a)
+229
View File
@@ -0,0 +1,229 @@
-- Exercise set 3a
--
-- * lists
-- * functional programming
module Set3a where
import Mooc.Todo
-- Some imports you'll need.
-- Do not add any other imports! :)
import Data.List
import Data.Char
------------------------------------------------------------------------------
-- Ex 1: implement the function maxBy that takes as argument a
-- measuring function (of type a -> Int) and two values (of type a).
--
-- maxBy should apply the measuring function to both arguments and
-- return the argument for which the measuring function returns a
-- higher value.
--
-- Examples:
--
-- maxBy (*2) 3 5 ==> 5
-- maxBy length [1,2,3] [4,5] ==> [1,2,3]
-- maxBy head [1,2,3] [4,5] ==> [4,5]
maxBy :: (a -> Int) -> a -> a -> a
maxBy measure a b = todo
------------------------------------------------------------------------------
-- Ex 2: implement the function mapMaybe that takes a function and a
-- Maybe value. If the value is Nothing, it returns Nothing. If it is
-- a Just, it updates the contained value using the function.
--
-- Examples:
-- mapMaybe length Nothing ==> Nothing
-- mapMaybe length (Just "abc") ==> Just 3
mapMaybe :: (a -> b) -> Maybe a -> Maybe b
mapMaybe f x = todo
------------------------------------------------------------------------------
-- Ex 3: implement the function mapMaybe2 that works like mapMaybe
-- except it combines two Maybe values using a function of two
-- arguments.
--
-- Examples:
-- mapMaybe2 take (Just 2) (Just "abcd") ==> Just "ab"
-- mapMaybe2 div (Just 6) (Just 3) ==> Just 2
-- mapMaybe2 div Nothing (Just 3) ==> Nothing
-- mapMaybe2 div (Just 6) Nothing ==> Nothing
mapMaybe2 :: (a -> b -> c) -> Maybe a -> Maybe b -> Maybe c
mapMaybe2 f x y = todo
------------------------------------------------------------------------------
-- Ex 4: define the functions firstHalf and palindrome so that
-- palindromeHalfs returns the first halfs of all palindromes in its
-- input.
--
-- Example:
-- palindromeHalfs ["abba", "cat", "racecar"]
-- ==> ["ab","race"]
--
-- What types should firstHalf and palindrome have? Give them type
-- annotations.
--
-- Note! Do not change the definition of palindromeHalfs
palindromeHalfs :: [String] -> [String]
palindromeHalfs xs = map firstHalf (filter palindrome xs)
firstHalf = todo
palindrome = todo
------------------------------------------------------------------------------
-- Ex 5: Implement a function capitalize that takes in a string and
-- capitalizes the first letter of each word in it.
--
-- You should probably define a helper function capitalizeFirst that
-- capitalizes the first letter of a string.
--
-- These functions will help:
-- - toUpper :: Char -> Char from the module Data.Char
-- - words :: String -> [String]
-- - unwords :: [String] -> String
--
-- Example:
-- capitalize "goodbye cruel world" ==> "Goodbye Cruel World"
capitalize :: String -> String
capitalize = todo
------------------------------------------------------------------------------
-- Ex 6: powers k max should return all the powers of k that are less
-- than or equal to max. For example:
--
-- powers 2 5 ==> [1,2,4]
-- powers 3 30 ==> [1,3,9,27]
-- powers 2 2 ==> [1,2]
--
-- You can assume that k is at least 2.
--
-- Hints:
-- * k^max > max
-- * the function takeWhile
powers :: Int -> Int -> [Int]
powers n max = todo
------------------------------------------------------------------------------
-- Ex 7: implement a functional while loop. That is, a function while
-- that that takes an updating function, a checking function and an
-- initial value. While should repeatedly apply the updating function
-- to the initial value as long as the value passes the checking function.
-- Finally, the value that doesn't pass the check is returned.
--
-- Examples:
--
-- while odd (+1) 1 ==> 2
--
-- while (<=4) (+1) 0 ==> 5
--
-- let check [] = True
-- check ('A':xs) = False
-- check _ = True
-- in while check tail "xyzAvvt"
-- ==> Avvt
while :: (a->Bool) -> (a->a) -> a -> a
while check update initial = todo
------------------------------------------------------------------------------
-- Ex 8: another version of a while loop. This time, the check
-- function returns an Either value. Keep iterating on Right values,
-- stop on a Left value.
--
-- Examples (see definition of step below):
-- whileEither (step 100) 1 ==> 128
-- whileEither (step 1000) 3 ==> 1536
whileRight :: (a -> Either b a) -> a -> b
whileRight f x = todo
-- for the whileRight examples:
-- step k x doubles x if it's less than k
step :: Int -> Int -> Either Int Int
step k x = if x<k then Right (2*x) else Left x
------------------------------------------------------------------------------
-- Ex 9: given a list of strings and a length, return all strings that
-- * have the given length
-- * are made by catenating two input strings
--
-- Examples:
-- joinToLength 2 ["a","b","cd"] ==> ["aa","ab","ba","bb"]
-- joinToLength 5 ["a","b","cd","def"] ==> ["cddef","defcd"]
--
-- Hint! This is a great use for list comprehensions
joinToLength :: Int -> [String] -> [String]
joinToLength = todo
------------------------------------------------------------------------------
-- Ex 10: implement the operator +|+ that returns a list with the first
-- elements of its input lists.
--
-- Give +|+ a type signature.
--
-- Examples:
-- [1,2,3] +|+ [4,5,6] ==> [1,4]
-- [] +|+ [True] ==> [True]
-- [] +|+ [] ==> []
------------------------------------------------------------------------------
-- Ex 11: remember the lectureParticipants example from Lecture 2? We
-- used a value of type [Either String Int] to store some measurements
-- that might be missing. Implement the function sumRights which sums
-- all non-missing measurements in a list like this.
--
-- Challenge: look up the type of the either function. Implement
-- sumRights using the map & either functions instead of pattern
-- matching on lists or Eithers!
--
-- Examples:
-- sumRights [Right 1, Left "bad value", Right 2] ==> 3
-- sumRights [Left "bad!", Left "missing"] ==> 0
sumRights :: [Either a Int] -> Int
sumRights = todo
------------------------------------------------------------------------------
-- Ex 12: in this exercise you get to implement an interpreter for a
-- simple language. You should keep track of the x and y coordinates,
-- and interpret the following commands:
--
-- up -- increment y by one
-- down -- decrement y by one
-- left -- decrement x by one
-- right -- increment x by one
-- printX -- print value of x
-- printY -- print value of y
--
-- The interpreter will be a function of type [String] -> [String].
-- Its input is a list of commands, and its output is a list of the
-- results of the print commands in the input.
--
-- Both coordinates start at 0.
--
-- Examples:
--
-- interpreter ["up","up","up","printY","down","printY"] ==> ["3","2"]
-- interpreter ["up","right","right","printY","printX"] ==> ["1","2"]
--
-- Surprise! after you've implemented the function, try running this in GHCi:
-- interact (unlines . interpreter . lines)
-- after this you can enter commands on separate lines and see the
-- responses to them
--
-- Unfortunately the surprise might not work if you've implemented
-- your interpreter correctly but weirdly :(
interpreter :: [String] -> [String]
interpreter commands = todo
+187
View File
@@ -0,0 +1,187 @@
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
module Set3aTest where
import Data.Char
import Data.List
import Test.QuickCheck
import Mooc.Th
import Mooc.Test
import Set3a
main = score tests
tests = [(1,"maxBy",[ex1_maxBy])
,(2,"mapMaybe",[ex2_mapMaybe_Nothing, ex2_mapMaybe_Just_String, ex2_mapMaybe_Just_Int])
,(3,"mapMaybe2",[ex3_mapMaybe2])
,(4,"palindromeHalfs",[ex4_palindromeHalfs])
,(5,"capitalize",[ex5_capitalize_1, ex5_capitalize_2])
,(6,"powers",[ex6_powers])
,(7,"while",[ex7_while_number, ex7_while_string])
,(8,"whileRight",[ex8_whileRight_Left, ex8_whileRight_step])
,(9,"joinToLength",[ex9_1])
,(10,"+|+",[ex10])
,(11,"sumRights",[ex11])
,(12,"interpreter",[ex12_interpreter_1, ex12_interpreter_2])
]
-- -- -- -- -- --
letter = choose ('a','z')
word = listOf1 letter
ex1_maxBy = property $ do
t <- choose (0,20)
f <- choose (0,20) `suchThat` \f -> f/=t
let p True = t
p False = f
return $
counterexample ("let p True = "++show t++"; p False = "++show f++" in maxBy p False True") $
maxBy p False True ?== (t>f)
ex2_mapMaybe_Nothing =
$(testing' [|mapMaybe negate Nothing|]) (?==Nothing)
ex2_mapMaybe_Just_String = forAllBlind word $ \w ->
counterexample ("mapMaybe length (Just " ++ show w ++ ")") $
mapMaybe length (Just w) ?== Just (length w)
ex2_mapMaybe_Just_Int = forAll_ $ \(i::Int) ->
counterexample ("mapMaybe negate (Just " ++ show i ++ ")") $
mapMaybe negate (Just i) ?== Just (negate i)
ex3_mapMaybe2 = forAll_ $ \(Positive i,Positive j) ->
let t :: Maybe Integer -> Maybe Integer -> Maybe Integer -> Property
t a b exp = counterexample ("mapMaybe div " ++ show' a ++ " " ++ show' b) $ mapMaybe2 div a b ?== exp
in conjoin [t (Just i) (Just j) (Just (div i j))
,t Nothing (Just j) Nothing
,t (Just i) Nothing Nothing
,t Nothing Nothing Nothing]
unpalindrome = word `suchThat` \w -> w /= reverse w
ex4_palindromeHalfs = property $ do
half1 <- word
let palindrome1 = half1 ++ reverse half1
half2 <- word
let palindrome2 = half2 ++ reverse (init half2)
un1 <- listOf1 unpalindrome
un2 <- listOf1 unpalindrome
un3 <- listOf1 unpalindrome
let input = un1 ++ [palindrome1] ++ un2 ++ [palindrome2] ++ un3
let expected = [half1, half2]
let palindromeHalfs xs = map firstHalf (filter palindrome xs)
return $ $(testing [|palindromeHalfs input|]) (?==expected)
ex5_capitalize_1 = property $ do
cap <- letter
w1 <- word
w2 <- word
return $ $(testing [|capitalize (cap:w1++" "++cap:w2)|]) (?==(toUpper cap:w1++" "++toUpper cap:w2))
ex5_capitalize_2 = property $ do
ws <- listOf1 word
let input = unwords ws
let positions = init $ scanl (+) 0 $ map (succ.length) ws
p <- elements positions
q <- elements [0..length input - 1]
return . $(testing [|capitalize input|]) $ \v ->
conjoin [counterexample ("char at index "++show p) $ v !! p ?== toUpper (input !! p)
,not (elem q positions) ==> counterexample ("char at index "++show q) (v !! q ?== input !! q)]
ex6_powers = property $ do
n <- choose (2,5)
len <- choose (1,10)
end <- choose (n^(len-1),n^len-1)
return $ $(testing [|powers n end|]) $ \p -> conjoin
[counterexample "all smaller than end" $ all (<=end) p
,counterexample "in ascending order" $ p == sort p
,counterexample "length" $ length p ?== len
,counterexample "all powers of n" $ all (check n) p]
where check n 0 = True
check n 1 = True
check n k
| k `mod` n == 0 = check n (div k n)
| otherwise = False
ex7_while_number = property $ do
n <- choose (0,20 :: Integer)
return $ counterexample ("while (/="++show n++") (+1) 0") $
while (/=n) (+1) 0 ?== n
ex7_while_string = property $ do
n <- word
let w = n++n
p = (/=n)
return $ counterexample ("while (/="++show n++") tail "++show w) $
while p tail w == n
ex8_whileRight_Left = forAllBlind word $ \w ->
forAllBlind (choose (1::Int,10)) $ \i ->
counterexample ("let f _ = Left " ++ show w ++ " in whileRight f " ++ show i) $
let f _ = Left w in whileRight f i ?== w
ex8_whileRight_step = property $ do
let step :: Int -> Int -> Either Int Int
step k x = if x<k then Right (2*x) else Left x
limit <- choose (1,1000)
start <- elements [1,3,5]
let log = ceiling . logBase 2 . fromIntegral
divUp x y = ceiling (fromIntegral x / fromIntegral y)
answer = start * 2 ^ (log (limit `divUp` start))
return $ counterexample ("whileRight (step " ++ show limit ++ ") " ++ show start) $
whileRight (step limit) start ?== answer
ex9_1 = property $ do
w <- word
v <- word `suchThat` diffLength w
let target = length w + length v
cruft <- listOf1 word
let input = sort $
([w,v]++) $
nubBy (\x y -> length x + length y == target) $
filter (\x -> 2 * length x /= target) $
filter (\x -> diffLength x v && diffLength x w) $
cruft
output = [w++v, v++w]
return $ $(testing [|joinToLength target input|]) (hasElements output)
where diffLength a b = length a /= length b
ex10 = $(withDefined "+|+") $ \op ->
forAll_ $ \(x::Int,y::Int,xs'::[Int],ys'::[Int]) ->
let xs = x:xs'
ys = y:ys'
in conjoin [counterexample (show xs ++ " +|+ " ++ show ys) $ op xs ys ?== [x,y]
,counterexample (show xs ++ " +|+ []") $ op xs [] ?== [x]
,counterexample ("[] +|+ " ++ show xs) $ op [] xs ?== [x]]
ex11 = property $ do
is <- listOf (choose (0,10))
es <- listOf word
input <- shuffle (map Right is ++ map Left es)
return $ $(testing [|sumRights input|]) (?==sum is)
ex12_interpreter_1 = property $ do
up <- choose (0,10)
right <- choose (0,10)
down <- choose (1,3)
left <- choose (0,1)
let first = replicate up "up" ++ replicate right "right" ++ ["printY","printX"]
second = replicate down "down" ++ replicate left "left" ++ ["printY","printX"]
input = first ++ second
output = [show up, show right, show (up-down), show (right-left)]
return $ counterexample ("interpreter "++show input) $
interpreter input ?== output
ex12_interpreter_2 = property $ do
nums <- vectorOf 4 $ choose (0,10)
let diffs = zipWith (-) nums (0:nums)
f x | x<0 = replicate (negate x) "down"
| otherwise = replicate x "up"
input = concatMap (\x -> f x ++ ["printY"]) diffs
output = map show nums
return $ $(testing [|interpreter input|]) (?== output)
+163
View File
@@ -0,0 +1,163 @@
-- Exercise set 3b
--
-- This is a special exercise set. The exercises are about
-- implementing list functions using recursion and pattern matching,
-- without using any standard library functions. For this reason,
-- you'll be working in a limited environment where almost none of the
-- standard library is available.
--
-- The tests will check that you haven't added imports :)
{-# LANGUAGE NoImplicitPrelude #-}
module Set3b where
import Mooc.LimitedPrelude
import Mooc.Todo
------------------------------------------------------------------------------
-- Ex 1: given numbers start, count and end, build a list that starts
-- with with count copies of start and ends with end.
--
-- Use recursion and the : operator to build the list.
--
-- Examples:
-- buildList 1 5 2 ==> [1,1,1,1,1,2]
-- buildList 7 0 3 ==> [3]
buildList :: Int -> Int -> Int -> [Int]
buildList start count end = todo
------------------------------------------------------------------------------
-- Ex 2: given i, build the list of sums [1, 1+2, 1+2+3, .., 1+2+..+i]
--
-- Use recursion and the : operator to build the list.
--
-- Ps. you'll probably need a recursive helper function
sums :: Int -> [Int]
sums i = todo
------------------------------------------------------------------------------
-- Ex 3: define a function mylast that returns the last value of the
-- given list. For an empty list, a provided default value is
-- returned.
--
-- Use only pattern matching and recursion (and the list constructors : and [])
--
-- Examples:
-- mylast 0 [] ==> 0
-- mylast 0 [1,2,3] ==> 3
mylast :: a -> [a] -> a
mylast def xs = todo
------------------------------------------------------------------------------
-- Ex 4: safe list indexing. Define a function indexDefault so that
-- indexDefault xs def i
-- gets the element at index i in the list xs. If i is not a valid
-- index, def is returned.
--
-- Use only pattern matching and recursion (and the list constructors : and [])
--
-- This time, implement indexDefault using pattern matching and
-- recursion.
--
-- Examples:
-- indexDefault [True] 1 False ==> False
-- indexDefault [10,20,30] 0 7 ==> 10
-- indexDefault [10,20,30] 2 7 ==> 30
-- indexDefault [10,20,30] 3 7 ==> 7
-- indexDefault ["a","b","c"] (-1) "d" ==> "d"
indexDefault :: [a] -> Int -> a -> a
indexDefault xs i def = todo
------------------------------------------------------------------------------
-- Ex 5: define a function that checks if the given list is in
-- increasing order.
--
-- Use only pattern matching and recursion.
sorted :: [Int] -> Bool
sorted xs = todo
------------------------------------------------------------------------------
-- Ex 6: compute the partial sums of the given list like this:
--
-- sumsOf [a,b,c] ==> [a,a+b,a+b+c]
-- sumsOf [a,b] ==> [a,a+b]
-- sumsOf [] ==> []
--
-- Use pattern matching and recursion (and the list constructors : and [])
sumsOf :: [Int] -> [Int]
sumsOf xs = todo
------------------------------------------------------------------------------
-- Ex 7: implement the function merge that merges two sorted lists of
-- Ints into a sorted list
--
-- Use only pattern matching and recursion (and the list constructors : and [])
--
-- Examples:
-- merge [1,3,5] [2,4,6] ==> [1,2,3,4,5,6]
-- merge [1,1,6] [1,2] ==> [1,1,1,2,6]
merge :: [Int] -> [Int] -> [Int]
merge xs ys = todo
------------------------------------------------------------------------------
-- Ex 8: define the function mymaximum that takes a list and a
-- function bigger :: a -> a -> Bool and returns the
-- biggest of the list, according to the comparing function.
--
-- An initial biggest value is provided to give you something to
-- return for empty lists.
--
-- Examples:
-- mymaximum (>) 3 [] ==> 3
-- mymaximum (>) 0 [1,3,2] ==> 3
-- mymaximum (>) 4 [1,3,2] ==> 4 -- initial value was biggest
-- mymaximum (<) 4 [1,3,2] ==> 1 -- note changed biggerThan
-- mymaximum (\_ _ -> True) 4 [1,3,2]
-- ==> 2 -- new value is always the biggest, so returns the last
mymaximum :: (a -> a -> Bool) -> a -> [a] -> a
mymaximum bigger initial xs = todo
------------------------------------------------------------------------------
-- Ex 9: define a version of map that takes a two-argument function
-- and two lists. Example:
-- map2 f [x,y,z,w] [a,b,c] ==> [f x a, f y b, f z c]
--
-- Use recursion and pattern matching. Do not use any library functions.
map2 :: (a -> b -> c) -> [a] -> [b] -> [c]
map2 f as bs = todo
------------------------------------------------------------------------------
-- Ex 10: implement the function maybeMap, which works a bit like a
-- combined map & filter.
---
-- maybeMap is given a list ([a]) and a function of type a -> Maybe b.
-- This function is called for all values in the list. If the function
-- returns Just x, x will be in the result list. If the function
-- returns Nothing, nothing gets added to the result list.
--
-- Examples:
--
-- let f x = if x>0 then Just (2*x) else Nothing
-- in maybeMap f [0,1,-1,4,-2,2]
-- ==> [2,8,4]
--
-- maybeMap Just [1,2,3]
-- ==> [1,2,3]
--
-- maybeMap (\x -> Nothing) [1,2,3]
-- ==> []
maybeMap :: (a -> Maybe b) -> [a] -> [b]
maybeMap f xs = todo
+109
View File
@@ -0,0 +1,109 @@
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
module Set3bTest where
import Data.List
import Test.QuickCheck
import Mooc.Th
import Mooc.Test
import Set3b
main = score tests
tests = [(1,"buildList",[imports, ex1_buildList])
,(2,"sums",[imports, ex2_sums])
,(3,"mylast",[imports, ex3_mylast_nonempty, ex3_mylast_empty])
,(4,"indexDefault",[imports, ex4_indexDefault_ok, ex4_indexDefault_ok])
,(5,"sorted",[imports, ex5_sorted_empty, ex5_sorted])
,(6,"sumsOf",[imports, ex6_sumsOf])
,(7,"merge",[imports, ex7_merge])
,(8,"mymaximum",[imports, ex8_mymaximum_max, ex8_mymaximum_min, ex8_mymaximum_empty])
,(9,"map2",[imports, ex9_map2_1, ex9_map2_2])
,(10,"maybeMap",[imports, ex10_maybeMap_1, ex10_maybeMap_2])
]
-- -- -- -- -- --
imports = $(importsOnly "Set3b" ["GHC.Num", "GHC.Base", "GHC.Classes", "GHC.Types",
"Mooc.Todo", "Mooc.LimitedPrelude"])
ex1_buildList = property $ do
start <- choose (0,20)
count <- choose (0,10)
end <- choose (30,40)
return $ $(testing [|buildList start count end|]) (?==(replicate count start ++ [end]))
ex2_sums = property $ do
i <- choose (1,30)
return $ $(testing [|sums i|]) (?==scanl1 (+) [1..i])
ex3_mylast_nonempty = forAll_ $ \(NonEmpty xs::NonEmptyList Integer) ->
$(testing [|mylast 0 xs|]) (?== last xs)
ex3_mylast_empty = forAll_ $ \(b::Bool) ->
$(testing [|mylast b ([]::[Bool])|]) (?== b)
ex4_indexDefault_ok = property $ do
ws <- listOf1 arbitrary :: Gen [Int]
i <- choose (0,length ws - 1)
def <- arbitrary
return $ $(testing [|indexDefault ws i def|]) (?==ws!!i)
ex4_indexDefault_fail = property $ do
is <- listOf1 arbitrary :: Gen [Int]
i <- choose (0,10)
def <- arbitrary
let neg = negate i - 1
let over = length is + i
return $ conjoin [$(testing [|indexDefault is neg def|]) (?==def)
,$(testing [|indexDefault is over def|]) (?==def)]
ex5_sorted_empty =
$(testing [|sorted ([]::[Int])|]) (?== True)
ex5_sorted = forAll_ $ \xs ->
let s = sort xs
in conjoin [$(testing [|sorted xs|]) (?== (s == xs))
,$(testing [|sorted s|]) (?== True)]
ex6_sumsOf = forAll_ $ \xs -> $(testing [|sumsOf xs|]) (?== scanl1 (+) xs)
ex7_merge = forAll_ $ \(xs,ys) ->
$(testing [|merge (sort xs) (sort ys)|]) (?== sort (xs ++ ys))
ex8_mymaximum_max = forAll_ $ \(NonEmpty xs :: NonEmptyList Int) ->
counterexample ("mymaximum (>) 0 " ++ show xs) $
mymaximum (>) 0 xs ?== max 0 (maximum xs)
ex8_mymaximum_min = forAll_ $ \(NonEmpty xs :: NonEmptyList Int) ->
counterexample ("mymaximum (<) 10000 " ++ show xs) $
mymaximum (<) 10000 xs ?== min 10000 (minimum xs)
ex8_mymaximum_empty = property $ do
i <- choose (0,10) :: Gen Int
return $ counterexample ("mymaximum (<) "++show i++" []") $ mymaximum (<) i [] ?== i
ex9_map2_1 = forAll_ $ \(i::[Int],j::[Bool]) ->
counterexample ("map2 const "++show i++" "++show j) $
map2 const i j ?== take (length j) i
ex9_map2_2 = forAll_ $ \(is::[Int],j::Int) ->
let js = replicate (length is) j
in counterexample ("map2 (+) "++show is++" "++show js) $
map2 (+) is js ?== map (+j) is
ex10_maybeMap_1 = forAll_ $ \bs ->
counterexample ("let f True = Just True; f False = Nothing in maybeMap f "++show bs) $
maybeMap f bs ?== filter id bs
where f True = Just True
f False = Nothing
ex10_maybeMap_2 = forAll_ $ \(is :: [Int]) ->
counterexample ("let f x = if x>0 then Just (2*x) else Nothing\
\in maybeMap f "++show is) $
maybeMap f is ?== map (2*) (filter (>0) is)
where f x = if x>0 then Just (2*x) else Nothing