Examples of different syntaxes for function application in validators

This commit is contained in:
Logan McGrath 2021-08-13 13:03:19 -07:00
parent 05e4a3f552
commit 7699137716
2 changed files with 67 additions and 30 deletions

View File

@ -1,39 +1,48 @@
module Homework.Ch01 where
-- This calls reverse on toDigitsRev because I somehow did this backwards by default.
toDigits :: Integer -> [Integer]
toDigits = rev [] . toDigitsRev
toDigits = go []
where
rev acc (x : xs) = rev (x : acc) xs
rev acc [] = acc
go acc 0 = acc
go acc n = go (n `mod` 10 : acc) (n `div` 10)
revDigits :: [Integer] -> [Integer]
revDigits = go []
where
go acc (x : xs) = go (x : acc) xs
go acc [] = acc
-- I don't know how I managed it, but turning the number into an array already reversed it?
toDigitsRev :: Integer -> [Integer]
toDigitsRev n
| n < 1 = []
| otherwise =
let leftDigit = n `mod` 10
shiftedDigits = n `div` 10
in leftDigit : toDigitsRev shiftedDigits
toDigitsRev = revDigits . toDigits
doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther (odd' : even' : rest) = odd' : (even' * 2) : doubleEveryOther rest
doubleEveryOther rest = rest
doubleEveryOther = revDigits . go []
where
go acc (first : second : rest) = go ((second * 2) : first : acc) rest
go acc [last'] = last' : acc
go acc [] = acc
sumDigits :: [Integer] -> Integer
sumDigits = sumDigits' 0 . flattenDigits [] . eachToDigits []
sumDigits = sumDigits' . flattenDigits . eachToDigits
where
eachToDigits acc (x : xs) = eachToDigits (toDigits x : acc) xs
eachToDigits acc [] = acc
eachToDigits = foldDigits [] (\n acc -> toDigits n : acc)
flattenDigits = foldDigits [] (++)
sumDigits' = foldDigits 0 (+)
flattenDigits acc ((x : xs) : rest) = flattenDigits (x : acc) (xs : rest)
flattenDigits acc ([] : rest) = flattenDigits acc rest
flattenDigits acc [] = acc
foldDigits acc f (x : xs) = foldDigits (f x acc) f xs
foldDigits acc _ [] = acc
sumDigits' acc (x : xs) = sumDigits' (acc + x) xs
sumDigits' acc [] = acc
validateWithParens :: Integer -> Bool
validateWithParens n = f n `mod` 10 == 0
where
f n' = sumDigits (doubleEveryOther (toDigitsRev n'))
validate :: Integer -> Bool
validate n = f n `mod` 10 == 0
validateWithDollars :: Integer -> Bool
validateWithDollars n = f n `mod` 10 == 0
where
f n' = sumDigits $ doubleEveryOther $ toDigitsRev n'
validateWithCompose :: Integer -> Bool
validateWithCompose n = f n `mod` 10 == 0
where
f = sumDigits . doubleEveryOther . toDigitsRev

View File

@ -44,10 +44,38 @@ spec = describe "Credit Card Validation" $ do
it "splits doubled digits into single digits and sums all single digits together" $ do
sumDigits [16, 7, 12, 5] `shouldBe` 22
describe "validate" $ do
it "returns True for a valid credit card number" $ do
validate 5105105105105100 `shouldBe` True
validate 2223577120017656 `shouldBe` True
it "returns False for invalid credit card number" $ do
validate 5105105105105101 `shouldBe` False
validate 2223573420017656 `shouldBe` False
context "validators" $ do
let validators =
[ ("validateWithParens", validateWithParens),
("validateWithDollars", validateWithDollars),
("validateWithCompose", validateWithCompose)
]
accept num = (num, True)
reject num = (num, False)
labelExpectation num expectIsValid
| expectIsValid = "accepts " ++ show num
| otherwise = "rejects " ++ show num
nums =
[ accept 5105105105105100,
accept 2223577120017656,
accept 371449635398431,
accept 6011000990139424,
accept 30569309025904,
accept 3566002020360505,
reject 5105105105105101,
reject 5420933878724339,
reject 5506923616306249,
reject 3999292939485618
]
runExpectation validate' num expectedResult =
it (labelExpectation num expectedResult) $ do
validate' num `shouldBe` expectedResult
runValidator label validate' =
describe label $ do
sequence_ (uncurry (runExpectation validate') <$> nums)
sequence_ (uncurry runValidator <$> validators)