mirror of
https://github.com/iritmaximus/haskell.git
synced 2026-10-12 19:13:39 +03:00
add Set2, Set3a, Set3b
This commit is contained in:
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user