Skip to content

Commit b462b18

Browse files
committed
Add solutions for "Using QuickCheck" from ch14
Numbers 8, 9, 10 and 11 still need to be completed.
1 parent c26f037 commit b462b18

File tree

2 files changed

+179
-1
lines changed

2 files changed

+179
-1
lines changed

ch14/chex/UsingQuickCheck.hs

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
module UsingQuickCheck where
2+
3+
import Test.QuickCheck
4+
import Data.List (sort)
5+
6+
7+
-- 1.
8+
half :: Fractional a => a -> a
9+
half x = x / 2
10+
11+
12+
halfIdentity :: Fractional a => a -> a
13+
halfIdentity = (*2) . half
14+
15+
16+
prop_halfIdentity :: (Eq a, Fractional a) => a -> Bool
17+
prop_halfIdentity x = halfIdentity x == x
18+
19+
20+
qc_halfIdentity :: IO ()
21+
qc_halfIdentity = do
22+
quickCheck (prop_halfIdentity :: Float -> Bool)
23+
quickCheck (prop_halfIdentity :: Double -> Bool)
24+
25+
26+
-- 2.
27+
-- for any list you apply sort to this property should hold
28+
listOrdered :: (Ord a) => [a] -> Bool
29+
listOrdered xs =
30+
snd $ foldr go (Nothing, True) xs
31+
where
32+
go _ status@(_, False) = status
33+
go y (Nothing, t) = (Just y, t)
34+
go y (Just x, _) = (Just y, x >= y)
35+
36+
-- See https://wiki.haskell.org/File:Right-fold-transformation.png
37+
--
38+
-- listOrdered [1, 2]
39+
-- = snd $ 1 --- go --- go
40+
-- / \
41+
-- 2 (Nothing, True)
42+
-- = snd $ 1 --- go --- (Just 2, True)
43+
-- = snd $ (Just 1, True)
44+
-- = True
45+
46+
47+
prop_sortListOrdered :: (Ord a) => [a] -> Bool
48+
prop_sortListOrdered = listOrdered . sort
49+
50+
51+
qc_sortListOrdered :: IO ()
52+
qc_sortListOrdered = do
53+
quickCheck (prop_sortListOrdered :: [Int] -> Bool)
54+
quickCheck (prop_sortListOrdered :: [String] -> Bool)
55+
56+
57+
-- 3.
58+
prop_plusAssociative :: (Eq a, Num a) => a -> a -> a -> Bool
59+
prop_plusAssociative x y z = x + (y + z) == (x + y) + z
60+
61+
62+
prop_plusCommutative :: (Eq a, Num a) => a -> a -> Bool
63+
prop_plusCommutative x y = x + y == y + x
64+
65+
66+
qc_plus :: IO ()
67+
qc_plus = do
68+
quickCheck (prop_plusAssociative :: Int -> Int -> Int -> Bool)
69+
quickCheck (prop_plusCommutative :: Int -> Int -> Bool)
70+
71+
72+
-- 4.
73+
prop_multAssociative :: (Eq a, Num a) => a -> a -> a -> Bool
74+
prop_multAssociative x y z = x * (y * z) == (x * y) * z
75+
76+
77+
prop_multCommutative :: (Eq a, Num a) => a -> a -> Bool
78+
prop_multCommutative x y = x * y == y * x
79+
80+
81+
qc_mult :: IO ()
82+
qc_mult = do
83+
quickCheck (prop_multAssociative :: Int -> Int -> Int -> Bool)
84+
quickCheck (prop_multCommutative :: Int -> Int -> Bool)
85+
86+
87+
-- 5.
88+
-- N.B. We need to ignore division by 0 in both cases.
89+
90+
prop_quotRem :: (Eq a, Integral a) => a -> a -> Bool
91+
prop_quotRem x y = y == 0 || (quot x y) * y + (rem x y) == x
92+
93+
94+
prop_divMod :: (Eq a, Integral a) => a -> a -> Bool
95+
prop_divMod x y = y == 0 || (div x y) * y + (mod x y) == x
96+
97+
98+
qc_quotRem :: IO ()
99+
qc_quotRem = do
100+
quickCheck (prop_quotRem :: Int -> Int -> Bool)
101+
102+
103+
qc_divMod :: IO ()
104+
qc_divMod = do
105+
quickCheck (prop_divMod :: Int -> Int -> Bool)
106+
107+
108+
-- 6.
109+
-- Is (^) associative or commutative?
110+
111+
prop_powerAssociative :: (Eq a, Integral a) => a -> a -> a -> Bool
112+
prop_powerAssociative x y z = (x ^ y) ^ z == x ^ (y ^ z)
113+
114+
115+
prop_powerCommutative :: (Eq a, Integral a) => a -> a -> Bool
116+
prop_powerCommutative x y = x ^ y == y ^ x
117+
118+
119+
qc_powerAssociative :: IO ()
120+
qc_powerAssociative = do
121+
quickCheck (prop_powerAssociative :: Int -> Int -> Int -> Bool)
122+
-- It fails for x=0, y=0, z=0 since
123+
-- LHS: (0 ^ 0) ^ 0 = 1 ^ 0 = 1
124+
-- RHS: 0 ^ (0 ^ 0) = 0 ^ 1 = 0
125+
-- LHS /= RHS
126+
127+
128+
qc_powerCommutative :: IO ()
129+
qc_powerCommutative = do
130+
quickCheck (prop_powerCommutative :: Int -> Int -> Bool)
131+
-- It fails for x=0, y=1
132+
-- LHS: 0 ^ 1 = 0
133+
-- RHS: 1 ^ 0 = 1
134+
-- LHS /= RHS
135+
136+
137+
-- Just my curiousity
138+
-- I wonder what values it would use to show that addition does not
139+
-- distribute over multiplication
140+
141+
prop_addDistribution :: (Eq a, Num a) => a -> a -> a -> Bool
142+
prop_addDistribution x y z = x + (y * z) == (x * y) + (x * z)
143+
144+
145+
qc_addDistribution :: IO ()
146+
qc_addDistribution = do
147+
quickCheck (prop_addDistribution :: Int -> Int -> Int -> Bool)
148+
-- It fails for x=0, y=1, z=1
149+
-- LHS: 0 + (1 * 1) = 0 + 1 = 1
150+
-- RHS: (0 * 1) + (0 * 1) = 0 + 0 = 0
151+
-- LHS /= RHS
152+
153+
154+
-- 7.
155+
prop_reverseId :: (Eq a) => [a] -> Bool
156+
prop_reverseId xs = (reverse . reverse) xs == xs
157+
158+
159+
qc_reverseId :: IO ()
160+
qc_reverseId = quickCheck (prop_reverseId :: [Char] -> Bool)
161+
162+
163+
-- 8.
164+
-- To be completed.
165+
166+
167+
-- 9.
168+
-- To be completed.
169+
170+
171+
-- 10.
172+
-- To be completed.
173+
174+
175+
-- 11.
176+
-- To be completed.

ch14/chex/chex.cabal

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ library
1515
hs-source-dirs: .
1616
default-language: Haskell2010
1717
ghc-options: -Wall -fwarn-tabs
18-
exposed-modules: WordNumber
18+
exposed-modules: UsingQuickCheck
19+
, WordNumber
1920
, WordNumberTest
2021
build-depends: base >= 4.7 && < 5
2122
, hspec
23+
, QuickCheck

0 commit comments

Comments
 (0)