{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TupleSections #-}
module Main (main) where
import System.Exit
(exitFailure, exitSuccess)
import Data.Functor.Identity
import Hedgehog
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
import Control.Monad.Reader
(ReaderT(..), runReaderT)
import Control.Monad.State
(StateT(..), evalStateT)
import Control.Monad.Writer
(Writer, execWriter, tell)
import Text.Read
(readMaybe)
import Data.IParser
-- fmap id == id
prop_functor_identity :: Property
prop_functor_identity = property $ do
x <- forAll $ Gen.integral (Range.linear 0 100)
let p = parser (pure x) pure :: IParser Identity Identity Int Int
decode (fmap id p) === id (decode p)
encode (fmap id p) x === id (encode p x)
-- fmap (f . g) == fmap f . fmap g
prop_functor_composition :: Property
prop_functor_composition = property $ do
x <- forAll $ Gen.integral (Range.linear 0 100)
y <- forAll $ Gen.integral (Range.linear 0 100)
z <- forAll $ Gen.integral (Range.linear 0 100)
let p = parser (pure val) pure :: IParser Identity Identity (Int, (Int, Int)) (Int, (Int, Int))
f = fst
g = snd
val = (x,(y,z))
decode (fmap (f . g) p) === decode (fmap f . fmap g $ p)
encode (fmap (f . g) p) val === encode (fmap f . fmap g $ p) val
-- pure id <*> v
prop_applicative_identity :: Property
prop_applicative_identity = property $ do
x <- forAll $ Gen.integral (Range.linear 0 100)
let p = pure x :: IParser Identity Identity Int Int
decode (pure id <*> p) === pure x
prop_bidirectional :: Property
prop_bidirectional = property $ do
x <- forAll $ Gen.integral (Range.linear 0 100)
let int = parser (ReaderT readMaybe) (\x -> x <$ tell [show x])
runReaderT (decode int) (head (execWriter (encode int x))) === Just x
data Person
= Person { name :: String, age :: Int }
deriving (Show, Eq)
prop_compose :: Property
prop_compose = property $ do
person <- forAll (Person <$> Gen.string (Range.linear 0 10) Gen.unicode <*> Gen.integral (Range.linear 10 30))
let int = parser (StateT $ \(x:xs) -> (,xs) <$> readMaybe x) (\x -> x <$ tell [show x])
string = parser (StateT $ \(x:xs) -> Just (x,xs)) (\x -> x <$ tell [x])
p = Person <$> name .= string <*> age .= int
encoded = execWriter (encode p person)
evalStateT (decode p) encoded === Just person
main :: IO ()
main = do
result <- checkParallel $$(discover)
if result then exitSuccess else exitFailure