new Set 5a Ex 12, improve tests Set 6 Ex 7, renumber Set 4

This commit is contained in:
Joel Kaasinen
2020-08-02 14:21:23 +03:00
parent dee7fd75d9
commit 78ae3a474a
6 changed files with 188 additions and 58 deletions
+34 -33
View File
@@ -38,37 +38,7 @@ myMaximum (x:xs) = foldr maxHelper x xs
maxHelper = todo
------------------------------------------------------------------------------
-- Ex 3: get the first element of a list with a fold. Define
-- headHelper so that the given definition of myHead works.
--
-- Start by giving headHelper a type.
--
-- Examples:
-- myHead [] ==> Nothing
-- myHead [1,2,3] ==> Just 1
myHead :: [a] -> Maybe a
myHead xs = foldr headHelper Nothing xs
headHelper = todo
------------------------------------------------------------------------------
-- Ex 4: get the last element of a list with a fold. Define lasthelper
-- so that the given definition of myLast works.
--
-- Start by giving lastHelper a type.
--
-- Examples:
-- myLast [] ==> Nothing
-- myLast [1,2,3] ==> Just 3
myLast :: [a] -> Maybe a
myLast xs = foldr lastHelper Nothing xs
lastHelper = todo
------------------------------------------------------------------------------
-- Ex 5: compute the sum and length of a list with a fold. Define
-- Ex 3: compute the sum and length of a list with a fold. Define
-- slHelper and slStart so that the given definition of sumAndLength
-- works. This could be used to compute the average of a list.
--
@@ -86,7 +56,7 @@ slStart = todo
slHelper = todo
------------------------------------------------------------------------------
-- Ex 6: implement concat with with a fold. Define concatHelper and
-- Ex 4: implement concat with with a fold. Define concatHelper and
-- concatStart so that the given definition of myConcat joins inner lists
-- of a list.
--
@@ -101,7 +71,7 @@ concatStart = todo
concatHelper = todo
------------------------------------------------------------------------------
-- Ex 7: get all occurrences of the largest number in a list with a
-- Ex 5: get all occurrences of the largest number in a list with a
-- fold. Implement largestHelper so that the given definition of largest works.
--
-- Examples:
@@ -114,3 +84,34 @@ largest xs = foldr largestHelper [] xs
largestHelper = todo
------------------------------------------------------------------------------
-- Ex 6: get the first element of a list with a fold. Define
-- headHelper so that the given definition of myHead works.
--
-- Start by giving headHelper a type.
--
-- Examples:
-- myHead [] ==> Nothing
-- myHead [1,2,3] ==> Just 1
myHead :: [a] -> Maybe a
myHead xs = foldr headHelper Nothing xs
headHelper = todo
------------------------------------------------------------------------------
-- Ex 7: get the last element of a list with a fold. Define lasthelper
-- so that the given definition of myLast works.
--
-- Start by giving lastHelper a type.
--
-- Examples:
-- myLast [] ==> Nothing
-- myLast [1,2,3] ==> Just 3
myLast :: [a] -> Maybe a
myLast xs = foldr lastHelper Nothing xs
lastHelper = todo
+25 -24
View File
@@ -15,11 +15,11 @@ main = score tests
tests = [(1,"countNothings",[ex1_countNothings])
,(2,"myMaximum",[ex2_myMaximum])
,(3,"myHead",[ex3_myHead_empty, ex3_myHead_full])
,(4,"myLast",[ex4_myLast_empty, ex4_myLast_full])
,(5,"sumAndLength",[ex5_sumAndLength])
,(6,"myConcat",[ex6_myConcat])
,(7,"largest",[ex7_largest])]
,(3,"sumAndLength",[ex3_sumAndLength])
,(4,"myConcat",[ex4_myConcat])
,(5,"largest",[ex5_largest])
,(6,"myHead",[ex6_myHead_empty, ex6_myHead_full])
,(7,"myLast",[ex7_myLast_empty, ex7_myLast_full])]
ex1_countNothings = property $ do
justs <- fmap (map Just) $ listOf (choose (0::Int,10))
@@ -37,35 +37,36 @@ ex2_myMaximum = property $ do
counterexample ("xs = "++show xs) $
$(testing' [|foldr maxHelper x xs|]) (?==maximum (x:xs))
ex3_myHead_empty =
$(testing' [|foldr headHelper Nothing []|]) (?==(Nothing::Maybe Bool))
ex3_myHead_full =
forAll_ $ \(NonEmpty xs::NonEmptyList Int) ->
counterexample ("xs = "++show xs) $
$(testing' [|foldr headHelper Nothing xs|]) (?==Just (head xs))
ex4_myLast_empty =
$(testing' [|foldr lastHelper Nothing []|]) (?==(Nothing::Maybe Bool))
ex4_myLast_full =
forAll_ $ \(NonEmpty xs::NonEmptyList Int) ->
counterexample ("xs = "++show xs) $
$(testing' [|foldr lastHelper Nothing xs|]) (?==Just (last xs))
niceDouble = fmap ((/2).fromIntegral) (arbitrary :: Gen Int)
ex5_sumAndLength =
ex3_sumAndLength =
forAllBlind (listOf niceDouble) $ \(ds::[Double]) ->
counterexample ("ds = "++show ds) $
$(testing' [|foldr slHelper slStart ds|]) (?==(sum ds, length ds))
ex6_myConcat =
ex4_myConcat =
forAll_ $ \(xs :: [[Int]]) ->
counterexample ("xs = "++show xs) $
$(testing' [|foldr concatHelper concatStart xs|]) (?==concat xs)
ex7_largest =
ex5_largest =
forAll_ $ \(NonEmpty (xs :: [Int])) ->
counterexample ("xs = "++show xs) $
$(testing' [|foldr largestHelper [] xs|]) (?==filter (==maximum xs) xs)
ex6_myHead_empty =
$(testing' [|foldr headHelper Nothing []|]) (?==(Nothing::Maybe Bool))
ex6_myHead_full =
forAll_ $ \(NonEmpty xs::NonEmptyList Int) ->
counterexample ("xs = "++show xs) $
$(testing' [|foldr headHelper Nothing xs|]) (?==Just (head xs))
ex7_myLast_empty =
$(testing' [|foldr lastHelper Nothing []|]) (?==(Nothing::Maybe Bool))
ex7_myLast_full =
forAll_ $ \(NonEmpty xs::NonEmptyList Int) ->
counterexample ("xs = "++show xs) $
$(testing' [|foldr lastHelper Nothing xs|]) (?==Just (last xs))
+62
View File
@@ -258,3 +258,65 @@ fromNat n = todo
toNat :: Int -> Maybe Nat
toNat z = todo
------------------------------------------------------------------------------
-- Ex 12: While pleasingly simple in its definition, the Nat datatype is not
-- very efficient computationally. Instead of the unary Peano natural numbers,
-- computers use binary numbers.
--
-- Binary numbers are like decimal numbers, except that binary numbers have
-- only two digits (called bits), 0 and 1. The table below gives some
-- examples:
--
-- decimal | binary
-- ----------------
-- 0 | 0
-- 1 | 1
-- 2 | 10
-- 7 | 111
-- 44 | 101100
--
-- For allowing arbitrarily long binary numbers, our representation, the
-- datatype Bin, includes a special End constructor for denoting the end of
-- the binary number. In order to make computation with Bin easier, the bits
-- are represented in increasing order by significance (i.e. "backwards").
-- Consider the Bin numbers O (I (I End)), representing 110 in binary or
-- 6 in decimal, and I (I (O End)) that represents 011 in binary or 3 in
-- decimal. The most significant (last) bit, the bit I, of O (I (I End)) is
-- greater than the bit O, which is the most significant bit of I (I (O End)).
-- Therefore, O (I (I End)) is greater than I (I (O End)).
--
-- Your task is to write functions prettyPrint, fromBin, and toBin that
-- convert Bin to human-readable string, Bin to Int, and Int to Bin
-- respectively.
--
-- Examples:
-- prettyPrint End ==> ""
-- prettyPrint (O End) ==> "0"
-- prettyPrint (I End) ==> "1"
-- prettyPrint (O (O (I (O (I End))))) ==> "10100"
-- map fromBinary [O End, I End, O (I End), I (I End), O (O (I End)),
-- I (O (I End))]
-- ==> [0, 1, 2, 3, 4, 5]
-- fromBinary (I (I (O (O (I (O (I (O End)))))))) ==> 83
-- fromBinary (I (I (O (O (I (O (I End))))))) ==> 83
-- map toBinary [0..5] ==>
-- [O End,I End,O (I End),I (I End),O (O (I End)),I (O (I End))]
-- toBinary 57 ==> I (O (O (I (I (I End)))))
--
data Bin = End | O Bin | I Bin
-- This function increments a binary number by one.
inc :: Bin -> Bin
inc End = I End
inc (O b) = I b
inc (I b) = O (inc b)
prettyPrint :: Bin -> String
prettyPrint = todo
fromBin :: Bin -> Int
fromBin = todo
toBin :: Int -> Bin
toBin = todo
+30
View File
@@ -23,6 +23,10 @@ tests = [(1,"Vehicle",[ex1])
,(9,"OneOrTwo",[ex9])
,(10,"KeyVals",[ex10_type, ex10_string_bool, ex10_int_int])
,(11,"Nat",[ex11_to, ex11_from, ex11_just, ex11_nothing])
,(12,"Bin",[ex12_from_zero, ex12_to_zero, ex12_to_from_zero
, ex12_from_to_zero, ex12_from_one, ex12_to_one
, ex12_to_from_one, ex12_from_to_one, ex12_to_from
, ex12_from_to])
]
-- -- -- -- -- -- -- --
@@ -185,3 +189,29 @@ ex11_just = forAll_ $ \(n :: Nat) ->
(toNat (fromNat n) ?== Just n)
ex11_nothing = forAll_ $ \(Negative (z :: Int)) ->
$(testing [|toNat z|]) (?== Nothing)
instance Arbitrary Bin where
arbitrary = do
bs <- arbitrary :: Gen [Bool]
return $ foldr (\x b -> if x then I b else O b) (I End) (take 8 bs)
ex12_from_zero =
counterexample ("fromBin (O End)") (fromBin (O End) ?== 0)
ex12_to_zero =
counterexample ("toBin 0") (toBin 0 ?== O End)
ex12_to_from_zero =
counterexample ("toBin (fromBin (O End))") (toBin (fromBin (O End)) ?== O End)
ex12_from_to_zero =
counterexample ("fromBin (toBin 0)") (fromBin (toBin 0) ?== 0)
ex12_from_one =
counterexample ("fromBin (I End)") (fromBin (I End) ?== 1)
ex12_to_one =
counterexample ("toBin 0") (toBin 1 ?== I End)
ex12_to_from_one =
counterexample ("toBin (fromBin (I End))") (toBin (fromBin (I End)) ?== I End)
ex12_from_to_one =
counterexample ("fromBin (toBin 1)") (fromBin (toBin 1) ?== 1)
ex12_to_from = forAll_ $ \(b :: Bin) ->
counterexample ("toBin (fromBin (" ++ show b ++ "))") (toBin (fromBin b) ?== b)
ex12_from_to = forAll_ $ \(n :: Int) -> n < 0 .||.
counterexample ("fromBin (toBin (" ++ show n ++ "))") (fromBin (toBin n) ?== n)
+36 -1
View File
@@ -86,6 +86,11 @@ ex6_milk =
conjoin [$(testing [|price [Just (Milk milk1), Nothing, Just (Milk milk2)]|]) (?==(15*milk1+15*milk2))
,$(testing [|price [Nothing, Nothing, Nothing :: Maybe Milk]|]) (?==0)]
instance Arbitrary Number where
arbitrary = do
b <- arbitrary
if b then arbitrary >>= return . Finite else return Infinite
ex7_eq_check =
$(withInstance "Eq" "Number" [|(==) :: Number -> Number -> Bool|]) $ \(==) ->
forAll_ $ \i ->
@@ -94,6 +99,34 @@ ex7_eq_check =
,$(testing [|Finite i == Infinite|]) (?==False)
,$(testing [|Infinite == Infinite|]) (?==True)]
ex7_trichotomy =
$(withInstance "Eq" "Number" [|(==) :: Number -> Number -> Bool|]) $ \(==) ->
forAll_ $ \(x :: Number) ->
forAll_ $ \(y :: Number) ->
(x /= y) ==> counterexample
(show x ++ " /= " ++ show y ++ ", but neither " ++
show x ++ " < " ++ show y ++ " or " ++
show x ++ " > " ++ show y ++ " was true")
(x < y || x > y)
ex7_reflexivity =
$(withInstance "Eq" "Number" [|(==) :: Number -> Number -> Bool|]) $ \(==) ->
forAll_ $ \(x :: Number) ->
$(testing [| x <= x |]) (?==True)
ex7_antisymmetry =
$(withInstance "Eq" "Number" [|(==) :: Number -> Number -> Bool|]) $ \(==) ->
forAll_ $ \(x :: Number) ->
forAll_ $ \(y :: Number) ->
(x <= y && y <= x) ==> $(testing [| x == y |]) (?==True)
ex7_transitivity =
$(withInstance "Eq" "Number" [|(==) :: Number -> Number -> Bool|]) $ \(==) ->
forAll_ $ \(x :: Number) ->
forAll_ $ \(y :: Number) ->
forAll_ $ \(z :: Number) ->
(x <= y && y <= z) ==> $(testing [| x <= z |]) (?==True)
ex7_finite =
$(withInstance "Ord" "Number" [|max :: Number -> Number -> Number|]) $ \max ->
forAll_ $ \i ->
@@ -273,7 +306,9 @@ tests = [(1,"Eq Country",[ex1])
,(4,"Eq List",[ex4_eq, ex4_neq])
,(5,"Price",[ex5_egg, ex5_milk])
,(6,"Price List",[ex6_egg, ex6_milk])
,(7,"Ord Number",[ex7_eq_check, ex7_finite, ex7_infinite])
,(7,"Ord Number",[ ex7_eq_check, ex7_trichotomy, ex7_reflexivity
, ex7_antisymmetry, ex7_transitivity, ex7_finite
, ex7_infinite ])
,(8,"Eq RationalNumber",[ex8_refl, ex8_eq])
,(9,"simplify",[ex9_prime, ex9_eq])
,(10,"Num RationalNumber",[ex10_add_zero, ex10_add_commut, ex10_add_whole, ex10_add
+1
View File
@@ -3392,6 +3392,7 @@ If I define an instance for <code>Num</code>, I also get an instance for <code>F
<p>By the way, these functions are available as <code>Data.List.NonEmpty.head</code> and <code>Data.List.NonEmpty.last</code> along with many other useful functions.</p>
<p>In summary, if you write types that represent all possible cases for your values, and then write functions that handle those cases, your code will be simple and correct.</p>
<h2 id="monoids"><span class="header-section-number">7.3</span> Monoids</h2>
<!-- TODO: Give an example of a semigroup that is not a monoid. -->
<!-- TODO: move to the end of the lecture? -->
<h3 id="what"><span class="header-section-number">7.3.1</span> What?</h3>
<p>A simple but useful abstraction that Haskell libraries use is that of the <em>monoid</em>. (Not to be confused with a <em>monad</em>!) In Haskell terms, <code>Monoid</code> is a type class that contains the function <code>&lt;&gt;</code> and the constant <code>mempty</code>.</p>