Last active
May 19, 2022 11:09
-
-
Save mjgpy3/93fd0cc1e997f4b75d3cd009588ebe25 to your computer and use it in GitHub Desktop.
maybe-haskell-homework-bad-functor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Lib | |
( someFunc | |
, DeciderOutcome(..) | |
, badFmap1 | |
, badFmap2 | |
, badFmap3 | |
) where | |
data DeciderOutcome a | |
= Outcome a | |
-- ^ We got an outcome (e.g. dice roll of 2, coin flip of heads) | |
| ErrorFlewOffTable | |
-- ^ Our decider didn't properly land on the table | |
| ErrorLandedOnItsEdge | |
-- ^ Our decider defied physics and landed on its edge/corner/side | |
deriving (Eq, Show) | |
instance Functor DeciderOutcome where | |
fmap f (Outcome v) = Outcome $ f v | |
fmap _ ErrorFlewOffTable = ErrorFlewOffTable | |
fmap _ ErrorLandedOnItsEdge = ErrorLandedOnItsEdge | |
-- Flip flops the errors | |
-- 1 case | |
badFmap1 :: (a -> b) -> DeciderOutcome a -> DeciderOutcome b | |
badFmap1 f (Outcome v) = Outcome $ f v | |
badFmap1 _ ErrorFlewOffTable = ErrorLandedOnItsEdge | |
badFmap1 _ ErrorLandedOnItsEdge = ErrorFlewOffTable | |
-- Changes a success to errors (lossy success and/or errors) | |
-- 2 * 2 * 2 cases = 8 cases | |
badFmap2 :: (a -> b) -> DeciderOutcome a -> DeciderOutcome b | |
badFmap2 _ (Outcome _) = ErrorLandedOnItsEdge | |
badFmap2 _ ErrorFlewOffTable = ErrorLandedOnItsEdge | |
badFmap2 _ ErrorLandedOnItsEdge = ErrorFlewOffTable | |
-- Success but changes the error (lossy errors) | |
-- 2 cases | |
badFmap3 :: (a -> b) -> DeciderOutcome a -> DeciderOutcome b | |
badFmap3 f (Outcome v) = Outcome $ f v | |
badFmap3 _ ErrorFlewOffTable = ErrorFlewOffTable | |
badFmap3 _ ErrorLandedOnItsEdge = ErrorFlewOffTable | |
-- 11 bad cases. Also, using case analysis... | |
-- 3 possible definitions for 'Outcome v' case | |
-- 2 possible definitions for 'ErrorFlewOffTable' case | |
-- 2 possible definitions for 'ErrorLandedOnItsEdge' case | |
-- 1 lawful definition | |
-- | |
-- so, 3*2*2-1 = 11 | |
someFunc :: IO () | |
someFunc = putStrLn "someFunc" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Functor DeciderOutcome | |
identity | |
+++ OK, passed 100 tests. | |
compositions | |
+++ OK, passed 100 tests. | |
badFmap1 | |
identity FAILED [1] | |
compositions FAILED [2] | |
badFmap2 | |
identity FAILED [3] | |
compositions FAILED [4] | |
badFmap3 | |
identity FAILED [5] | |
compositions | |
+++ OK, passed 100 tests. | |
Failures: | |
test/Spec.hs:28:5: | |
1) badFmap1 identity | |
Falsified (after 2 tests): | |
Die32 ErrorLandedOnItsEdge | |
To rerun use: --match "/badFmap1/identity/" | |
test/Spec.hs:31:5: | |
2) badFmap1 compositions | |
Falsified (after 1 test and 6 shrinks): | |
{_->0} | |
{_->0} | |
Die32 ErrorFlewOffTable | |
To rerun use: --match "/badFmap1/compositions/" | |
test/Spec.hs:35:5: | |
3) badFmap2 identity | |
Falsified (after 1 test): | |
Die32 (Outcome 21) | |
To rerun use: --match "/badFmap2/identity/" | |
test/Spec.hs:38:5: | |
4) badFmap2 compositions | |
Falsified (after 1 test and 6 shrinks): | |
{_->0} | |
{_->0} | |
Die32 ErrorFlewOffTable | |
To rerun use: --match "/badFmap2/compositions/" | |
test/Spec.hs:42:5: | |
5) badFmap3 identity | |
Falsified (after 2 tests): | |
Die32 ErrorLandedOnItsEdge | |
To rerun use: --match "/badFmap3/identity/" | |
Randomized with seed 1516855505 | |
Finished in 0.0042 seconds | |
8 examples, 5 failures |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE ScopedTypeVariables #-} | |
import Test.Hspec | |
import Test.QuickCheck | |
import Control.Exception (evaluate) | |
import Lib | |
newtype Die32 = Die32 (DeciderOutcome Int) | |
deriving (Eq, Show) | |
instance Arbitrary Die32 where | |
arbitrary = | |
Die32 <$> oneof [ | |
Outcome <$> choose (1, 32) | |
, pure ErrorFlewOffTable | |
, pure ErrorLandedOnItsEdge | |
] | |
main :: IO () | |
main = hspec $ do | |
describe "Functor DeciderOutcome" $ do | |
it "identity" $ property $ \(Die32 die) -> | |
fmap id die == id die | |
it "compositions" $ property $ \(Fn (f :: Int -> Int)) (Fn (g :: Int -> Int)) (Die32 die) -> | |
fmap (f . g) die == (fmap f . fmap g) die | |
describe "badFmap1" $ do | |
it "identity" $ property $ \(Die32 die) -> | |
badFmap1 id die == id die | |
it "compositions" $ property $ \(Fn (f :: Int -> Int)) (Fn (g :: Int -> Int)) (Die32 die) -> | |
badFmap1 (f . g) die == (badFmap1 f . badFmap1 g) die | |
describe "badFmap2" $ do | |
it "identity" $ property $ \(Die32 die) -> | |
badFmap2 id die == id die | |
it "compositions" $ property $ \(Fn (f :: Int -> Int)) (Fn (g :: Int -> Int)) (Die32 die) -> | |
badFmap2 (f . g) die == (badFmap2 f . badFmap2 g) die | |
describe "badFmap3" $ do | |
it "identity" $ property $ \(Die32 die) -> | |
badFmap3 id die == id die | |
it "compositions" $ property $ \(Fn (f :: Int -> Int)) (Fn (g :: Int -> Int)) (Die32 die) -> | |
badFmap3 (f . g) die == (badFmap3 f . badFmap3 g) die |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment