parent
94d3695e64
commit
ae7d8db3db
13 changed files with 436 additions and 0 deletions
@ -0,0 +1,2 @@ |
||||
# Exercise: Optional Monoid |
||||
see src/Optional.hs |
@ -0,0 +1,2 @@ |
||||
# Exercise: Maybe Another Monoid |
||||
see src/First.hs |
@ -0,0 +1,2 @@ |
||||
# Chapter Exercises |
||||
see src/sem.hs |
Binary file not shown.
@ -0,0 +1,8 @@ |
||||
module Listy where |
||||
|
||||
newtype Listy a = Listy [a] deriving (Eq, Show) |
||||
|
||||
instance Monoid (Listy a) where |
||||
mempty = Listy [] |
||||
mappend (Listy l) (Listy l') = |
||||
Listy $ mappend l l' |
Binary file not shown.
Binary file not shown.
@ -0,0 +1,9 @@ |
||||
module ListyInstances where |
||||
|
||||
import Data.Monoid |
||||
import Listy |
||||
|
||||
instance Monoid (Listy a) where |
||||
mempty = Listy [] |
||||
mappend (Listy l) (Listy l') = |
||||
Listy $ mappend l l' |
Binary file not shown.
@ -0,0 +1,41 @@ |
||||
module First where |
||||
|
||||
import Optional |
||||
import Data.Monoid |
||||
import Test.QuickCheck |
||||
|
||||
monoidAssoc :: (Eq m, Monoid m) => m -> m -> m -> Bool |
||||
monoidAssoc a b c = (a <> (b <> c)) == ((a <> b) <> c) |
||||
|
||||
monoidLeftIdentity :: (Eq m, Monoid m) => m -> Bool |
||||
monoidLeftIdentity a = (mempty <> a) == a |
||||
|
||||
monoidRightIdentity :: (Eq m, Monoid m) => m -> Bool |
||||
monoidRightIdentity a = (a <> mempty) == a |
||||
|
||||
|
||||
newtype First' a = First' { getFirst' :: Optional a } deriving (Eq, Show) |
||||
|
||||
instance Monoid (First' a) where |
||||
mempty = First' Nada |
||||
mappend (First' Nada) a = a |
||||
mappend a _ = a |
||||
|
||||
instance Arbitrary a => Arbitrary (First' a) where |
||||
arbitrary = do |
||||
a <- arbitrary |
||||
frequency [(1, return $ First' Nada), (1, return $ First' (Only a))] |
||||
|
||||
firstMappend :: First' a -> First' a -> First' a |
||||
firstMappend = mappend |
||||
|
||||
type FirstMappend = First' String -> First' String -> First' String -> Bool |
||||
type FstId = First' String -> Bool |
||||
|
||||
main :: IO () |
||||
main = do |
||||
quickCheck (monoidAssoc :: FirstMappend) |
||||
quickCheck (monoidLeftIdentity :: FstId) |
||||
quickCheck (monoidRightIdentity :: FstId) |
||||
|
||||
|
@ -0,0 +1,9 @@ |
||||
module Optional where |
||||
|
||||
data Optional a = Nada | Only a deriving (Eq, Show) |
||||
|
||||
instance Monoid a => Monoid (Optional a) where |
||||
mempty = Nada |
||||
mappend Nada a = a |
||||
mappend a Nada = a |
||||
mappend (Only a) (Only b) = Only $ mappend a b |
@ -0,0 +1,22 @@ |
||||
module Madness where |
||||
|
||||
import Data.Monoid |
||||
|
||||
type Verb = String |
||||
type Adjective = String |
||||
type Adverb = String |
||||
type Noun = String |
||||
type Exclamation = String |
||||
|
||||
madlibbin' :: Exclamation -> Adverb -> Noun -> Adjective -> String |
||||
madlibbin' e adv noun adj = |
||||
e <> "! he said " <> |
||||
adv <> " as he jumped into his car " <> |
||||
noun <> " and drove off with his " <> |
||||
adj <> " wife." |
||||
|
||||
madlibbinBetter' :: Exclamation -> Adverb -> Noun -> Adjective -> String |
||||
madlibbinBetter' e adv noun adj = |
||||
mconcat [e, "! he said ", adv, " as he jumped into his car ", |
||||
noun, " and drove off with his ", adj, " wife."] |
||||
|
@ -0,0 +1,341 @@ |
||||
module SemMon where |
||||
|
||||
import Data.Semigroup (Semigroup, (<>), Sum, Product) |
||||
import Data.Monoid (Monoid) |
||||
import Test.QuickCheck |
||||
|
||||
-- Note: |
||||
-- So as to not have to rewrite all the mappend rules, all Monoid instance, |
||||
-- will require the type to also be a Semigroup. |
||||
|
||||
-- Semigroup |
||||
semigroupAssoc :: (Eq m, Semigroup m) => m -> m -> m -> Bool |
||||
semigroupAssoc a b c = (a <> (b <> c)) == ((a <> b) <> c) |
||||
-- Monoid |
||||
monoidAssoc :: (Eq m, Monoid m) => m -> m -> m -> Bool |
||||
monoidAssoc a b c = |
||||
(a `mappend` (b `mappend` c)) == ((a `mappend` b) `mappend` c) |
||||
|
||||
monoidLeftIdent :: (Eq m, Monoid m) => m -> Bool |
||||
monoidLeftIdent a = (mappend mempty a) == a |
||||
|
||||
monoidRightIdent :: (Eq m, Monoid m) => m -> Bool |
||||
monoidRightIdent a = (mappend a mempty) == a |
||||
|
||||
-- 1 |
||||
-- Semigroup |
||||
data Trivial = Trivial deriving (Eq, Show) |
||||
instance Semigroup Trivial where |
||||
_ <> _ = Trivial |
||||
instance Arbitrary Trivial where |
||||
arbitrary = return Trivial |
||||
type TrivAssoc = Trivial -> Trivial -> Trivial -> Bool |
||||
-- Monoid |
||||
instance Monoid Trivial where |
||||
mempty = Trivial |
||||
mappend = (<>) |
||||
type TrivId = Trivial -> Bool |
||||
|
||||
-- 2 |
||||
-- Semigroup |
||||
newtype Identity a = Identity a deriving (Eq, Show) |
||||
instance Semigroup a => Semigroup (Identity a) where |
||||
(Identity a) <> (Identity a') = Identity $ a <> a' |
||||
instance Arbitrary a => Arbitrary (Identity a) where |
||||
arbitrary = do |
||||
a <- arbitrary |
||||
return $ Identity a |
||||
type IdentityAssoc = Identity String -> |
||||
Identity String -> |
||||
Identity String -> |
||||
Bool |
||||
-- Monoid |
||||
instance (Semigroup a, Monoid a) => Monoid (Identity a) where |
||||
mempty = Identity mempty |
||||
mappend = (<>) |
||||
type IdentityId = Identity String -> Bool |
||||
|
||||
-- 3 |
||||
-- Semigroup |
||||
data Two a b = Two a b deriving (Eq, Show) |
||||
instance (Semigroup a, Semigroup b) => Semigroup (Two a b) where |
||||
(Two a b) <> (Two a' b') = Two (a <> a') (b <> b') |
||||
instance (Arbitrary a, Arbitrary b) => Arbitrary (Two a b) where |
||||
arbitrary = do |
||||
a <- arbitrary |
||||
b <- arbitrary |
||||
return $ Two a b |
||||
type TwoAssoc = Two (Sum Int) (Product Int) -> |
||||
Two (Sum Int) (Product Int) -> |
||||
Two (Sum Int) (Product Int) -> |
||||
Bool |
||||
-- Monoid |
||||
instance (Semigroup a, Semigroup b, Monoid a, Monoid b) |
||||
=> Monoid (Two a b) where |
||||
mempty = Two mempty mempty |
||||
mappend = (<>) |
||||
type TwoId = Two (Sum Int) (Product Int) -> Bool |
||||
|
||||
-- 4 |
||||
-- Semigroup |
||||
data Three a b c = Three a b c deriving (Eq, Show) |
||||
instance (Semigroup a, Semigroup b, Semigroup c) |
||||
=> Semigroup (Three a b c) where |
||||
(Three a b c) <> (Three a' b' c') = |
||||
Three (a <> a') (b <> b') (c <> c') |
||||
instance (Arbitrary a, Arbitrary b, Arbitrary c) |
||||
=> Arbitrary (Three a b c) where |
||||
arbitrary = do |
||||
a <- arbitrary |
||||
b <- arbitrary |
||||
c <- arbitrary |
||||
return $ Three a b c |
||||
type ThreeAssoc = Three (Sum Int) (Product Int) String -> |
||||
Three (Sum Int) (Product Int) String -> |
||||
Three (Sum Int) (Product Int) String -> |
||||
Bool |
||||
-- Monoid |
||||
instance (Semigroup a, Semigroup b, Semigroup c, Monoid a, Monoid b, Monoid c) |
||||
=> Monoid (Three a b c) where |
||||
mempty = Three mempty mempty mempty |
||||
mappend = (<>) |
||||
type ThreeId = Three (Sum Int) (Product Int) String -> Bool |
||||
|
||||
-- 5 |
||||
-- Semigroup |
||||
data Four a b c d = Four a b c d deriving (Eq, Show) |
||||
instance (Semigroup a, Semigroup b, Semigroup c, Semigroup d) |
||||
=> Semigroup (Four a b c d) where |
||||
(Four a b c d) <> (Four a' b' c' d') = |
||||
Four (a <> a') (b <> b') (c <> c') (d <> d') |
||||
instance (Arbitrary a, Arbitrary b, Arbitrary c, Arbitrary d) |
||||
=> Arbitrary (Four a b c d) where |
||||
arbitrary = do |
||||
a <- arbitrary |
||||
b <- arbitrary |
||||
c <- arbitrary |
||||
d <- arbitrary |
||||
return $ Four a b c d |
||||
type FourAssoc = Four (Sum Int) (Product Int) String Ordering -> |
||||
Four (Sum Int) (Product Int) String Ordering -> |
||||
Four (Sum Int) (Product Int) String Ordering -> |
||||
Bool |
||||
-- Monoid |
||||
instance (Semigroup a, Semigroup b, Semigroup c, Semigroup d, |
||||
Monoid a, Monoid b, Monoid c, Monoid d) => |
||||
Monoid (Four a b c d) where |
||||
mempty = Four mempty mempty mempty mempty |
||||
mappend = (<>) |
||||
type FourId = Four (Sum Int) (Product Int) String Ordering -> Bool |
||||
|
||||
-- 6 |
||||
-- Semigroup |
||||
newtype BoolConj = BoolConj Bool deriving (Eq, Show) |
||||
instance Semigroup BoolConj where |
||||
(BoolConj True) <> (BoolConj True) = BoolConj True |
||||
_ <> _ = BoolConj False |
||||
instance Arbitrary BoolConj where |
||||
arbitrary = do |
||||
b <- arbitrary |
||||
return $ BoolConj b |
||||
type BoolConjAssoc = BoolConj -> BoolConj -> BoolConj -> Bool |
||||
-- Monoid |
||||
instance Monoid BoolConj where |
||||
mempty = BoolConj True |
||||
mappend = (<>) |
||||
type BoolConjId = BoolConj -> Bool |
||||
|
||||
-- 7 |
||||
-- Semigroup |
||||
newtype BoolDisj = BoolDisj Bool deriving (Eq, Show) |
||||
instance Semigroup BoolDisj where |
||||
(BoolDisj False) <> (BoolDisj False) = BoolDisj False |
||||
_ <> _ = BoolDisj True |
||||
instance Arbitrary BoolDisj where |
||||
arbitrary = do |
||||
b <- arbitrary |
||||
return $ BoolDisj b |
||||
type BoolDisjAssoc = BoolDisj -> BoolDisj -> BoolDisj -> Bool |
||||
-- Monoid |
||||
instance Monoid BoolDisj where |
||||
mempty = BoolDisj False |
||||
mappend = (<>) |
||||
type BoolDisjId = BoolDisj -> Bool |
||||
|
||||
-- 8 |
||||
-- Semigroup |
||||
data Or a b = Fst a | Snd b deriving (Eq, Show) |
||||
instance Semigroup (Or a b) where |
||||
Snd a <> _ = Snd a |
||||
_ <> Snd a = Snd a |
||||
_ <> a = a |
||||
instance (Arbitrary a, Arbitrary b) => Arbitrary (Or a b) where |
||||
arbitrary = do |
||||
a <- arbitrary |
||||
b <- arbitrary |
||||
elements [Fst a, Snd b] |
||||
type OrAssoc = Or Int Float -> Or Int Float -> Or Int Float -> Bool |
||||
-- Monoid |
||||
-- not possible as there is no identity possible. |
||||
|
||||
-- 9 |
||||
-- Semigroup |
||||
newtype Combine a b = Combine { unCombine :: (a -> b)} |
||||
-- instance Semigroup b => Semigroup (a -> b) where |
||||
-- f <> g = \a -> f a <> g a |
||||
-- In other words, f and g are applied to the argument |
||||
-- and the results are mappended. |
||||
instance Semigroup b => Semigroup (Combine a b) where |
||||
f <> g = Combine $ (unCombine f) <> (unCombine g) |
||||
instance (CoArbitrary a, Arbitrary b) => Arbitrary (Combine a b) where |
||||
arbitrary = do |
||||
f <- arbitrary |
||||
return $ Combine f |
||||
instance Show (Combine a b) where |
||||
show _ = "Combine a b" -- needed for QuickCheck, no idea what to really |
||||
-- do about this. |
||||
semigroupAssoc' :: Int -> -- the input for the function |
||||
Combine Int String -> |
||||
Combine Int String -> |
||||
Combine Int String -> |
||||
Bool |
||||
semigroupAssoc' i f g h = |
||||
(unCombine (f <> (g <> h))) i == (unCombine ((f <> g) <> h)) i |
||||
-- Monoid |
||||
instance (Semigroup b, Monoid b) => Monoid (Combine a b) where |
||||
mempty = Combine $ \_ -> mempty -- f a <> mempty a = f a |
||||
-- mempty a <> f a = f a |
||||
-- f a = b, so mempty is of type b |
||||
mappend = (<>) |
||||
monoidAssoc' :: Int -> -- the input for the function |
||||
Combine Int String -> |
||||
Combine Int String -> |
||||
Combine Int String -> |
||||
Bool |
||||
monoidAssoc' i f g h = |
||||
(unCombine (f `mappend` (g `mappend` h))) i |
||||
== (unCombine ((f `mappend` g) `mappend` h)) i |
||||
|
||||
monoidLeftIdent' :: Int -> Combine Int String -> Bool |
||||
monoidLeftIdent' i f = (unCombine (mappend mempty f)) i == (unCombine f) i |
||||
|
||||
monoidRightIdent' :: Int -> Combine Int String -> Bool |
||||
monoidRightIdent' i f = (unCombine (mappend f mempty)) i == (unCombine f) i |
||||
|
||||
-- 10 |
||||
-- Semigroup |
||||
newtype Comp a = Comp { unComp :: (a -> a) } |
||||
instance Semigroup (Comp a) where |
||||
f <> g = Comp $ unComp f . unComp g |
||||
instance (CoArbitrary a, Arbitrary a) => Arbitrary (Comp a) where |
||||
arbitrary = do |
||||
f <- arbitrary |
||||
return $ Comp f |
||||
instance Show (Comp a) where |
||||
show _ = "Comp a" -- needed for QuickCheck, no idea what to really |
||||
-- do about this. |
||||
semigroupAssoc'' :: Int -> -- the input for the function |
||||
Comp Int -> |
||||
Comp Int -> |
||||
Comp Int -> |
||||
Bool |
||||
semigroupAssoc'' i f g h = |
||||
(unComp (f <> (g <> h))) i == (unComp ((f <> g) <> h)) i |
||||
-- Monoid |
||||
instance Monoid (Comp a) where |
||||
mempty = Comp id |
||||
mappend= (<>) |
||||
monoidAssoc'' :: Int -> |
||||
Comp Int -> |
||||
Comp Int -> |
||||
Comp Int -> |
||||
Bool |
||||
monoidAssoc'' i f g h = |
||||
(unComp (f `mappend` (g `mappend` h))) i |
||||
== (unComp ((f `mappend` g) `mappend` h)) i |
||||
|
||||
monoidLeftIdent'' :: Int -> Comp Int -> Bool |
||||
monoidLeftIdent'' i f = (unComp (mappend mempty f)) i == (unComp f) i |
||||
|
||||
monoidRightIdent'' :: Int -> Comp Int -> Bool |
||||
monoidRightIdent'' i f = (unComp (mappend f mempty)) i == (unComp f) i |
||||
|
||||
-- 8 |
||||
-- Monoid |
||||
newtype Mem s a = Mem { runMem :: s -> (a,s) } |
||||
instance Monoid a => Monoid (Mem s a) where |
||||
mempty = Mem $ \s -> (mempty, s) |
||||
mappend f g = Mem $ \s -> |
||||
let (a, s') = runMem g $ s |
||||
(a', s'') = runMem f $ s' |
||||
in (mappend a a', s'') |
||||
instance (CoArbitrary s, Arbitrary a, Arbitrary s) => Arbitrary (Mem s a) where |
||||
arbitrary = do |
||||
f <- arbitrary |
||||
return $ Mem f |
||||
instance Show (Mem s a) where |
||||
show _ = "Mem s a" |
||||
monoidAssoc''' :: Int -> |
||||
Mem Int String -> |
||||
Mem Int String -> |
||||
Mem Int String -> |
||||
Bool |
||||
monoidAssoc''' i f g h = |
||||
(runMem (f `mappend` (g `mappend` h))) i |
||||
== (runMem ((f `mappend` g) `mappend` h)) i |
||||
|
||||
monoidLeftIdent''' :: Int -> Mem Int String -> Bool |
||||
monoidLeftIdent''' i f = (runMem (mappend mempty f)) i == (runMem f) i |
||||
|
||||
monoidRightIdent''' :: Int -> Mem Int String -> Bool |
||||
monoidRightIdent''' i f = (runMem (mappend f mempty)) i == (runMem f) i |
||||
|
||||
main :: IO () |
||||
main = do |
||||
putStrLn "Semigroup tests" |
||||
quickCheck (semigroupAssoc :: TrivAssoc) |
||||
quickCheck (semigroupAssoc :: IdentityAssoc) |
||||
quickCheck (semigroupAssoc :: TwoAssoc) |
||||
quickCheck (semigroupAssoc :: ThreeAssoc) |
||||
quickCheck (semigroupAssoc :: FourAssoc) |
||||
quickCheck (semigroupAssoc :: BoolConjAssoc) |
||||
quickCheck (semigroupAssoc :: BoolDisjAssoc) |
||||
quickCheck (semigroupAssoc :: OrAssoc) |
||||
quickCheck semigroupAssoc' |
||||
quickCheck semigroupAssoc'' |
||||
|
||||
putStrLn "Monoid tests - Associativity" -- actually same as semigroup |
||||
quickCheck (monoidAssoc :: TrivAssoc) |
||||
quickCheck (monoidAssoc :: IdentityAssoc) |
||||
quickCheck (monoidAssoc :: TwoAssoc) |
||||
quickCheck (monoidAssoc :: ThreeAssoc) |
||||
quickCheck (monoidAssoc :: FourAssoc) |
||||
quickCheck (monoidAssoc :: BoolConjAssoc) |
||||
quickCheck (monoidAssoc :: BoolDisjAssoc) |
||||
quickCheck monoidAssoc' |
||||
quickCheck monoidAssoc'' |
||||
quickCheck monoidAssoc''' |
||||
|
||||
putStrLn "Monoid tests - Left Identity" |
||||
quickCheck (monoidLeftIdent :: TrivId) |
||||
quickCheck (monoidLeftIdent :: IdentityId) |
||||
quickCheck (monoidLeftIdent :: TwoId) |
||||
quickCheck (monoidLeftIdent :: ThreeId) |
||||
quickCheck (monoidLeftIdent :: FourId) |
||||
quickCheck (monoidLeftIdent :: BoolConjId) |
||||
quickCheck (monoidLeftIdent :: BoolDisjId) |
||||
quickCheck monoidLeftIdent' |
||||
quickCheck monoidLeftIdent'' |
||||
quickCheck monoidLeftIdent''' |
||||
|
||||
putStrLn "Monoid tests - Right Identity" |
||||
quickCheck (monoidRightIdent :: TrivId) |
||||
quickCheck (monoidRightIdent :: IdentityId) |
||||
quickCheck (monoidRightIdent :: TwoId) |
||||
quickCheck (monoidRightIdent :: ThreeId) |
||||
quickCheck (monoidRightIdent :: FourId) |
||||
quickCheck (monoidRightIdent :: BoolConjId) |
||||
quickCheck (monoidRightIdent :: BoolDisjId) |
||||
quickCheck monoidRightIdent' |
||||
quickCheck monoidRightIdent'' |
||||
quickCheck monoidRightIdent''' |
Loading…
Reference in new issue