mirror of
https://github.com/iritmaximus/haskell.git
synced 2026-10-12 19:13:39 +03:00
move recursion with helper functions to lecture 2
- move some exercises from Set1 to a new Set2b - rename Set2 to Set2a - one new exercise in Set2a - improvements to lecture 2 & lecture 3 texts
This commit is contained in:
+1
-126
@@ -80,7 +80,7 @@ checkPassword password = if password == "swordfish"
|
||||
-- Packages over 5000 grams cost a constant 6000 credits.
|
||||
--
|
||||
-- Write a function postagePrice that takes the weight of a package
|
||||
-- in, and returns the cost in credits.
|
||||
-- in grams, and returns the cost in credits.
|
||||
|
||||
postagePrice :: Int -> Int
|
||||
postagePrice = todo
|
||||
@@ -128,128 +128,3 @@ power = todo
|
||||
|
||||
ilog3 :: Integer -> Integer
|
||||
ilog3 = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 12: compute binomial coefficients using recursion. Binomial
|
||||
-- coefficients are defined by the following equations:
|
||||
--
|
||||
-- B(n,k) = B(n-1,k) + B(n-1,k-1)
|
||||
-- B(n,0) = 1
|
||||
-- B(0,k) = 0, when k>0
|
||||
--
|
||||
-- Hint! pattern matching is your friend.
|
||||
|
||||
binomial :: Integer -> Integer -> Integer
|
||||
binomial = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 13: implement the odd factorial function. Odd factorial is like
|
||||
-- factorial, but it only multiplies odd numbers.
|
||||
--
|
||||
-- Examples:
|
||||
-- oddFactorial 7 ==> 7*5*3*1 ==> 105
|
||||
-- oddFactorial 6 ==> 5*3*1 ==> 15
|
||||
|
||||
oddFactorial :: Integer -> Integer
|
||||
oddFactorial = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 14: implement the Euclidean Algorithm for finding the greatest
|
||||
-- common divisor:
|
||||
--
|
||||
-- Given two numbers, a and b,
|
||||
-- * if one is zero, return the other number
|
||||
-- * if not, subtract the smaller number from the larger one
|
||||
-- * replace the larger number with this new number
|
||||
-- * repeat
|
||||
--
|
||||
-- For example,
|
||||
-- myGcd 9 12 ==> 3
|
||||
-- In this case, the algorithm proceeds like this
|
||||
--
|
||||
-- a b
|
||||
--
|
||||
-- 9 12
|
||||
-- 9 (12-9)
|
||||
-- 9 3
|
||||
-- (9-3) 3
|
||||
-- 6 3
|
||||
-- (6-3) 3
|
||||
-- 3 3
|
||||
-- (3-3) 3
|
||||
-- 0 3
|
||||
--
|
||||
-- Background reading:
|
||||
-- * https://en.wikipedia.org/wiki/Euclidean_algorithm
|
||||
|
||||
myGcd :: Integer -> Integer -> Integer
|
||||
myGcd = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 15: Implement the function leftpad which adds space characters
|
||||
-- to the start of the string until it is long enough.
|
||||
--
|
||||
-- Examples:
|
||||
-- leftpad "foo" 5 ==> " foo"
|
||||
-- leftpad "13" 3 ==> " 13"
|
||||
-- leftpad "xxxxx" 3 ==> "xxxxx"
|
||||
--
|
||||
-- Tips:
|
||||
-- * you can combine strings with the ++ operator.
|
||||
-- * you can compute the length of a string with the length function
|
||||
|
||||
leftpad :: String -> Int -> String
|
||||
leftpad = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 16: let's make a countdown for a rocket! Given a number, you
|
||||
-- should produce a string that says "Ready!", counts down from the
|
||||
-- number, and then says "Liftoff!".
|
||||
--
|
||||
-- For example,
|
||||
-- countdown 4 ==> "Ready! 4... 3... 2... 1... Liftoff!"
|
||||
--
|
||||
-- Hints:
|
||||
-- * you can combine strings with the ++ operator
|
||||
-- * you can use the show function to convert a number into a string
|
||||
-- * you'll probably need a recursive helper function
|
||||
|
||||
countdown :: Integer -> String
|
||||
countdown = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 17: implement the function smallestDivisor that returns the
|
||||
-- smallest number (greater than 1) that divides the given number evenly.
|
||||
--
|
||||
-- That is, when
|
||||
-- smallestDivisor n ==> k
|
||||
-- we have
|
||||
-- n = t*k
|
||||
-- for some t.
|
||||
--
|
||||
-- Ps. your function doesn't need to work for inputs 0 and 1, but
|
||||
-- remember this in the next exercise!
|
||||
|
||||
smallestDivisor :: Integer -> Integer
|
||||
smallestDivisor = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 18: implement a function isPrime that checks if the given number
|
||||
-- is a prime number. Use the function smallestDivisor.
|
||||
--
|
||||
-- Ps. 0 and 1 are not prime numbers
|
||||
|
||||
isPrime :: Integer -> Bool
|
||||
isPrime = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 19: implement a function biggestPrimeAtMost that returns the
|
||||
-- biggest prime number that is less than or equal to the given
|
||||
-- number. Use the function isPrime you just defined.
|
||||
--
|
||||
-- Examples:
|
||||
-- biggestPrimeAtMost 3 ==> 3
|
||||
-- biggestPrimeAtMost 10 ==> 7
|
||||
|
||||
biggestPrimeAtMost :: Integer -> Integer
|
||||
biggestPrimeAtMost = todo
|
||||
|
||||
+1
-68
@@ -28,15 +28,7 @@ tests = [(1,"onetwo",[ex1_one_defined, ex1_one_type
|
||||
,property ex8_isZero_negative])
|
||||
,(9,"sumTo",[ex9_sumTo])
|
||||
,(10,"power",[ex10_power])
|
||||
,(11,"ilog3",[property ex11_ilog3])
|
||||
,(12,"binomial",[ex12_binomial])
|
||||
,(13,"oddFactorial",[ex13_oddFactorial])
|
||||
,(14,"myGcd",[ex14_myGcd])
|
||||
,(15,"leftpad",[property ex15_leftpad])
|
||||
,(16,"countdown",[ex16_countdown])
|
||||
,(17,"smallestDivisor",[ex17_smallestDivisor_prime, property ex17_smallestDivisor_comp])
|
||||
,(18,"isPrime",[ex18_isPrime])
|
||||
,(19,"biggestPrimeAtMost",[ex19_biggestPrimeAtMost])]
|
||||
,(11,"ilog3",[property ex11_ilog3])]
|
||||
|
||||
-- -- -- -- -- --
|
||||
|
||||
@@ -107,62 +99,3 @@ ex10_power =
|
||||
|
||||
ex11_ilog3 (Blind (Positive n)) =
|
||||
$(testing [|ilog3 n|]) (?== 1 + floor (logBase 3 $ fromIntegral n))
|
||||
|
||||
ex12_binomial =
|
||||
forAllBlind (elements [0..10]) $ \n ->
|
||||
forAllBlind (elements [0..n]) $ \k ->
|
||||
$(testing [|binomial n k|]) (?== f n `div` (f k * f (n-k)))
|
||||
where f n = product [1..n]
|
||||
|
||||
ex13_oddFactorial =
|
||||
forAllBlind (elements [1..15]) $ \n ->
|
||||
$(testing [|oddFactorial n|]) (?== f n)
|
||||
where f n = product [1,3..n]
|
||||
|
||||
ex14_myGcd =
|
||||
forAllBlind (elements [1..max]) $ \x ->
|
||||
forAllBlind (elements [1..max]) $ \y ->
|
||||
$(testing [|myGcd x y|]) (?== gcd x y)
|
||||
where max = 10000
|
||||
|
||||
ex15_leftpad =
|
||||
do text <- word
|
||||
ws <- listOf (return ' ')
|
||||
let res = ws++text
|
||||
let len = length res
|
||||
return $ $(testing [|leftpad text len|]) (?==res)
|
||||
|
||||
ex16_countdown =
|
||||
forAllBlind (elements [1..20]) $ \n ->
|
||||
$(testing [|countdown n|]) . was $ \v ->
|
||||
counterexample "should start with \"Ready!\"" (take 6 v ?== "Ready!")
|
||||
.&&.
|
||||
counterexample "should end with \"Liftoff!\"" (reverse (take 8 (reverse v)) ?== "Liftoff!")
|
||||
.&&.
|
||||
let cnt = init $ init $ intercalate "... " (map show [n,n-1..0])
|
||||
in counterexample ("should contain the string " ++ show cnt) (isInfixOf cnt v)
|
||||
|
||||
primes = go [2..]
|
||||
where go (x:xs) = x : go (filter (notDivBy x) xs)
|
||||
notDivBy x y = mod y x /= 0
|
||||
|
||||
ex17_smallestDivisor_prime = do
|
||||
forAllBlind (elements $ take 12 primes) $ \p ->
|
||||
$(testing [|smallestDivisor p|]) (?== p)
|
||||
|
||||
ex17_smallestDivisor_comp = do
|
||||
k <- (elements . take 10 $ primes)
|
||||
p <- (elements . take 20 . drop 10 $ primes)
|
||||
let n = k*p
|
||||
return $ $(testing [|smallestDivisor n|]) (?== k)
|
||||
|
||||
ex18_isPrime =
|
||||
forAllBlind (elements [0..max]) $ \n ->
|
||||
$(testing [|isPrime n|]) (?== elem n primes')
|
||||
where max = 20
|
||||
primes' = takeWhile (<=max) primes
|
||||
|
||||
ex19_biggestPrimeAtMost =
|
||||
forAllBlind (elements [2..max]) $ \n ->
|
||||
$(testing [|biggestPrimeAtMost n|]) (?== last (takeWhile (<=n) primes))
|
||||
where max = 100
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
-- * null
|
||||
|
||||
|
||||
module Set2 where
|
||||
module Set2a where
|
||||
|
||||
import Mooc.Todo
|
||||
|
||||
@@ -64,13 +64,25 @@ substring :: Int -> Int -> String -> String
|
||||
substring i j s = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 5: implement the function palindromify that chops a character
|
||||
-- Ex 5: check if a string is a palindrome. A palindrome is a string
|
||||
-- that is the same when read backwards.
|
||||
--
|
||||
-- Hint! There's a really simple solution to this. Don't overthink it!
|
||||
--
|
||||
-- Examples:
|
||||
-- isPalindrome "" ==> True
|
||||
-- isPalindrome "ABBA" ==> True
|
||||
-- isPalindrome "racecar" ==> True
|
||||
-- isPalindrome "AB" ==> False
|
||||
|
||||
isPalindrome :: String -> Bool
|
||||
isPalindrome str = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 6: implement the function palindromify that chops a character
|
||||
-- off the front _and_ back of a string until the result is a
|
||||
-- palindrome.
|
||||
--
|
||||
-- Hint: remember the function palindrome :: String -> Bool from the
|
||||
-- course material!
|
||||
--
|
||||
-- Examples:
|
||||
-- palindromify "ab" ==> ""
|
||||
-- palindromify "aaay" ==> "aa"
|
||||
@@ -81,7 +93,7 @@ palindromify :: String -> String
|
||||
palindromify s = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 6: implement safe integer devision, that is, a function that
|
||||
-- Ex 7: 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.
|
||||
@@ -94,7 +106,7 @@ safeDiv :: Integer -> Integer -> Maybe Integer
|
||||
safeDiv x y = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 7: implement a function greet that greets a person given a first
|
||||
-- Ex 8: 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.
|
||||
--
|
||||
@@ -106,8 +118,8 @@ greet :: String -> Maybe String -> String
|
||||
greet first last = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 8: safe list indexing. Define a function safeIndex so that
|
||||
-- safeIndex xs i
|
||||
-- Ex 9: safe list indexing. Define a function safeIndex so that
|
||||
-- sefeIndex xs i
|
||||
-- gets the element at index i in the list xs. If i is not a valid
|
||||
-- index, Nothing is returned.
|
||||
--
|
||||
@@ -122,7 +134,7 @@ safeIndex :: [a] -> Int -> Maybe a
|
||||
safeIndex xs i = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 9: another variant of safe division. This time you should use
|
||||
-- Ex 10: another variant of safe division. This time you should use
|
||||
-- Either to return a string error message.
|
||||
--
|
||||
-- Examples:
|
||||
@@ -133,7 +145,7 @@ eitherDiv :: Integer -> Integer -> Either String Integer
|
||||
eitherDiv x y = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 10: implement the function addEithers, which combines two values of type
|
||||
-- Ex 11: 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
|
||||
@@ -0,0 +1,124 @@
|
||||
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
|
||||
|
||||
module Set2aTest where
|
||||
|
||||
import Data.Char
|
||||
import Data.List
|
||||
import Test.QuickCheck
|
||||
|
||||
import Mooc.Th
|
||||
import Mooc.Test
|
||||
|
||||
import Set2a
|
||||
|
||||
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,"isPalindrome",[ex5_isPalindrome])
|
||||
,(6,"palindromify",[ex6_palindromify])
|
||||
,(7,"safeDiv",[ex7_safeDiv_zero, ex7_safeDiv_nonZero])
|
||||
,(8,"greet",[ex8_greet_nothing, ex8_greet_just])
|
||||
,(9,"safeIndex",[ex9_safeIndex_ok, ex9_safeIndex_fail])
|
||||
,(10,"eitherDiv",[ex10_eitherDiv_zero, ex10_eitherDiv_nonZero])
|
||||
,(11,"addEithers",[ex11_addEithers_both, ex11_addEithers_one, ex11_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_isPalindrome = forAllBlind word $ \w1 ->
|
||||
forAllBlind (word `suchThat` (/=reverse w1) `suchThat` ((>1).length)) $ \w2 ->
|
||||
conjoin [$(testing [|isPalindrome (w1 ++ w2)|]) (?==False)
|
||||
,$(testing [|isPalindrome (w1 ++ reverse w1)|]) (?==True)
|
||||
,$(testing [|isPalindrome (w1 ++ w2 ++ reverse w1)|]) (?==False)
|
||||
,$(testing [|isPalindrome (init w1 ++ reverse w1)|]) (?==True)]
|
||||
|
||||
|
||||
ex6_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)
|
||||
|
||||
ex7_safeDiv_zero = forAll_ $ \x ->
|
||||
$(testing [|safeDiv x 0|]) (?== Nothing)
|
||||
|
||||
ex7_safeDiv_nonZero = forAll_ $ \(x,y) ->
|
||||
(y/=0) ==> $(testing [|safeDiv x y|]) (?== Just (div x y))
|
||||
|
||||
ex8_greet_nothing = forAllBlind word $ \first ->
|
||||
$(testing [|greet first (Nothing :: Maybe String)|]) (?==("Hello, "++first++"!"))
|
||||
|
||||
ex8_greet_just = forAllBlind word $ \first ->
|
||||
forAllBlind word $ \last ->
|
||||
$(testing [|greet first (Just last)|]) (?==("Hello, "++first++" "++last++"!"))
|
||||
|
||||
ex9_safeIndex_ok = property $ do
|
||||
ws <- listOf1 word
|
||||
i <- choose (0,length ws - 1)
|
||||
return $ $(testing [|safeIndex ws i|]) (?==Just (ws!!i))
|
||||
|
||||
ex9_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)]
|
||||
|
||||
ex10_eitherDiv_zero = forAll_ $ \x ->
|
||||
$(testing [|eitherDiv x 0|]) (?== Left (show x++"/0"))
|
||||
|
||||
ex10_eitherDiv_nonZero = forAll_ $ \(x,y) ->
|
||||
(y/=0) ==> $(testing [|eitherDiv x y|]) (?== Right (div x y))
|
||||
|
||||
|
||||
ex11_addEithers_both = forAll_ $ \(x,y) ->
|
||||
$(testing [|addEithers (Right x :: Either String Int) (Right y :: Either String Int)|]) (?== Right (x+y))
|
||||
|
||||
ex11_addEithers_one = property $ do
|
||||
err <- fmap Left arbitrary
|
||||
int <- fmap Right arbitrary
|
||||
~[x,y] <- shuffle [err,int]
|
||||
return $ $(testing [|addEithers x y|]) (?==err)
|
||||
|
||||
ex11_addEithers_neither = forAll_ $ \(a,b) ->
|
||||
$(testing [|addEithers (Left a :: Either String Int) (Left b :: Either String Int)|]) (?==Left a)
|
||||
@@ -0,0 +1,131 @@
|
||||
module Set2b where
|
||||
|
||||
import Mooc.Todo
|
||||
|
||||
-- Some imports you'll need. Don't add other imports :)
|
||||
import Data.List
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 1: compute binomial coefficients using recursion. Binomial
|
||||
-- coefficients are defined by the following equations:
|
||||
--
|
||||
-- B(n,k) = B(n-1,k) + B(n-1,k-1)
|
||||
-- B(n,0) = 1
|
||||
-- B(0,k) = 0, when k>0
|
||||
--
|
||||
-- Hint! pattern matching is your friend.
|
||||
|
||||
binomial :: Integer -> Integer -> Integer
|
||||
binomial = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 2: implement the odd factorial function. Odd factorial is like
|
||||
-- factorial, but it only multiplies odd numbers.
|
||||
--
|
||||
-- Examples:
|
||||
-- oddFactorial 7 ==> 7*5*3*1 ==> 105
|
||||
-- oddFactorial 6 ==> 5*3*1 ==> 15
|
||||
|
||||
oddFactorial :: Integer -> Integer
|
||||
oddFactorial = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 3: implement the Euclidean Algorithm for finding the greatest
|
||||
-- common divisor:
|
||||
--
|
||||
-- Given two numbers, a and b,
|
||||
-- * if one is zero, return the other number
|
||||
-- * if not, subtract the smaller number from the larger one
|
||||
-- * replace the larger number with this new number
|
||||
-- * repeat
|
||||
--
|
||||
-- For example,
|
||||
-- myGcd 9 12 ==> 3
|
||||
-- In this case, the algorithm proceeds like this
|
||||
--
|
||||
-- a b
|
||||
--
|
||||
-- 9 12
|
||||
-- 9 (12-9)
|
||||
-- 9 3
|
||||
-- (9-3) 3
|
||||
-- 6 3
|
||||
-- (6-3) 3
|
||||
-- 3 3
|
||||
-- (3-3) 3
|
||||
-- 0 3
|
||||
--
|
||||
-- Background reading:
|
||||
-- * https://en.wikipedia.org/wiki/Euclidean_algorithm
|
||||
|
||||
myGcd :: Integer -> Integer -> Integer
|
||||
myGcd = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 4: Implement the function leftpad which adds space characters
|
||||
-- to the start of the string until it is long enough.
|
||||
--
|
||||
-- Examples:
|
||||
-- leftpad "foo" 5 ==> " foo"
|
||||
-- leftpad "13" 3 ==> " 13"
|
||||
-- leftpad "xxxxx" 3 ==> "xxxxx"
|
||||
--
|
||||
-- Tips:
|
||||
-- * you can combine strings with the ++ operator.
|
||||
-- * you can compute the length of a string with the length function
|
||||
|
||||
leftpad :: String -> Int -> String
|
||||
leftpad = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 5: let's make a countdown for a rocket! Given a number, you
|
||||
-- should produce a string that says "Ready!", counts down from the
|
||||
-- number, and then says "Liftoff!".
|
||||
--
|
||||
-- For example,
|
||||
-- countdown 4 ==> "Ready! 4... 3... 2... 1... Liftoff!"
|
||||
--
|
||||
-- Hints:
|
||||
-- * you can combine strings with the ++ operator
|
||||
-- * you can use the show function to convert a number into a string
|
||||
-- * you'll probably need a recursive helper function
|
||||
|
||||
countdown :: Integer -> String
|
||||
countdown = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 6: implement the function smallestDivisor that returns the
|
||||
-- smallest number (greater than 1) that divides the given number evenly.
|
||||
--
|
||||
-- That is, when
|
||||
-- smallestDivisor n ==> k
|
||||
-- we have
|
||||
-- n = t*k
|
||||
-- for some t.
|
||||
--
|
||||
-- Ps. your function doesn't need to work for inputs 0 and 1, but
|
||||
-- remember this in the next exercise!
|
||||
|
||||
smallestDivisor :: Integer -> Integer
|
||||
smallestDivisor = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 7: implement a function isPrime that checks if the given number
|
||||
-- is a prime number. Use the function smallestDivisor.
|
||||
--
|
||||
-- Ps. 0 and 1 are not prime numbers
|
||||
|
||||
isPrime :: Integer -> Bool
|
||||
isPrime = todo
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
-- Ex 8: implement a function biggestPrimeAtMost that returns the
|
||||
-- biggest prime number that is less than or equal to the given
|
||||
-- number. Use the function isPrime you just defined.
|
||||
--
|
||||
-- Examples:
|
||||
-- biggestPrimeAtMost 3 ==> 3
|
||||
-- biggestPrimeAtMost 10 ==> 7
|
||||
|
||||
biggestPrimeAtMost :: Integer -> Integer
|
||||
biggestPrimeAtMost = todo
|
||||
@@ -0,0 +1,83 @@
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
|
||||
module Set2bTest where
|
||||
|
||||
import Data.List
|
||||
import Test.QuickCheck
|
||||
|
||||
import Mooc.Th
|
||||
import Mooc.Test
|
||||
|
||||
import Set2b
|
||||
|
||||
main = score tests
|
||||
|
||||
tests = [(1,"binomial",[ex1_binomial])
|
||||
,(2,"oddFactorial",[ex2_oddFactorial])
|
||||
,(3,"myGcd",[ex3_myGcd])
|
||||
,(4,"leftpad",[property ex4_leftpad])
|
||||
,(5,"countdown",[ex5_countdown])
|
||||
,(6,"smallestDivisor",[ex6_smallestDivisor_prime, property ex6_smallestDivisor_comp])
|
||||
,(7,"isPrime",[ex7_isPrime])
|
||||
,(8,"biggestPrimeAtMost",[ex8_biggestPrimeAtMost])]
|
||||
|
||||
ex1_binomial =
|
||||
forAllBlind (elements [0..10]) $ \n ->
|
||||
forAllBlind (elements [0..n]) $ \k ->
|
||||
$(testing [|binomial n k|]) (?== f n `div` (f k * f (n-k)))
|
||||
where f n = product [1..n]
|
||||
|
||||
ex2_oddFactorial =
|
||||
forAllBlind (elements [1..15]) $ \n ->
|
||||
$(testing [|oddFactorial n|]) (?== f n)
|
||||
where f n = product [1,3..n]
|
||||
|
||||
ex3_myGcd =
|
||||
forAllBlind (elements [1..max]) $ \x ->
|
||||
forAllBlind (elements [1..max]) $ \y ->
|
||||
$(testing [|myGcd x y|]) (?== gcd x y)
|
||||
where max = 10000
|
||||
|
||||
word = listOf1 (choose ('a','z'))
|
||||
|
||||
ex4_leftpad =
|
||||
do text <- word
|
||||
ws <- listOf (return ' ')
|
||||
let res = ws++text
|
||||
let len = length res
|
||||
return $ $(testing [|leftpad text len|]) (?==res)
|
||||
|
||||
ex5_countdown =
|
||||
forAllBlind (elements [1..20]) $ \n ->
|
||||
$(testing [|countdown n|]) . was $ \v ->
|
||||
counterexample "should start with \"Ready!\"" (take 6 v ?== "Ready!")
|
||||
.&&.
|
||||
counterexample "should end with \"Liftoff!\"" (reverse (take 8 (reverse v)) ?== "Liftoff!")
|
||||
.&&.
|
||||
let cnt = init $ init $ intercalate "... " (map show [n,n-1..0])
|
||||
in counterexample ("should contain the string " ++ show cnt) (isInfixOf cnt v)
|
||||
|
||||
primes = go [2..]
|
||||
where go (x:xs) = x : go (filter (notDivBy x) xs)
|
||||
notDivBy x y = mod y x /= 0
|
||||
|
||||
ex6_smallestDivisor_prime = do
|
||||
forAllBlind (elements $ take 12 primes) $ \p ->
|
||||
$(testing [|smallestDivisor p|]) (?== p)
|
||||
|
||||
ex6_smallestDivisor_comp = do
|
||||
k <- (elements . take 10 $ primes)
|
||||
p <- (elements . take 20 . drop 10 $ primes)
|
||||
let n = k*p
|
||||
return $ $(testing [|smallestDivisor n|]) (?== k)
|
||||
|
||||
ex7_isPrime =
|
||||
forAllBlind (elements [0..max]) $ \n ->
|
||||
$(testing [|isPrime n|]) (?== elem n primes')
|
||||
where max = 20
|
||||
primes' = takeWhile (<=max) primes
|
||||
|
||||
ex8_biggestPrimeAtMost =
|
||||
forAllBlind (elements [2..max]) $ \n ->
|
||||
$(testing [|biggestPrimeAtMost n|]) (?== last (takeWhile (<=n) primes))
|
||||
where max = 100
|
||||
+1484
-1427
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user