packages feed

holmes-0.2.0.0: test/Test/Util/Laws.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module Test.Util.Laws where

import Control.Applicative (liftA2)
import Hedgehog
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range

semigroup_associativity :: (Eq x, Semigroup x, Show x) => Gen x -> Property
semigroup_associativity gen = property do
  x <- forAll gen
  y <- forAll gen
  z <- forAll gen

  x <> (y <> z) === (x <> y) <> z

monoid_identity :: (Eq x, Monoid x, Show x) => Gen x -> Property
monoid_identity gen = property do
  x <- forAll gen
  mempty <> x === x

semigroup_commutativity :: (Eq x, Semigroup x, Show x) => Gen x -> Property
semigroup_commutativity gen = property do
  x <- forAll gen
  y <- forAll gen

  x <> y === y <> x

semigroup_idempotence :: (Eq x, Semigroup x, Show x) => Gen x -> Property
semigroup_idempotence gen = property do
  x <- forAll gen

  x <> x === x

functor_identity :: (Eq (f x), Functor f, Show (f x)) => Gen (f x) -> Property
functor_identity gen = property do
  x <- forAll gen

  fmap id x === x

functor_composition :: (Eq (f Int), Functor f, Show (f Int)) => Gen (f Int) -> Property
functor_composition gen = property do
  x <- forAll gen
  y <- forAll $ Gen.int (Range.linear 0 100)
  z <- forAll $ Gen.int (Range.linear 0 100)

  fmap (+ y) (fmap (* z) x) === fmap ((+ y) . (* z)) x

applicative_identity :: (Applicative f, Eq (f x), Show (f x)) => Gen (f x) -> Property
applicative_identity gen = property do
  x <- forAll gen

  (pure id <*> x) === x

applicative_composition :: (Applicative f, Eq (f Int), Show (f Int)) => Gen (f Int) -> Property
applicative_composition gen = property do
  x <- forAll gen
  y <- forAll gen
  z <- forAll gen

  liftA2 (+) x (liftA2 (+) y z) === liftA2 (+) (liftA2 (+) x y) z

applicative_homomorphism :: forall f. (Applicative f, Eq (f Int), Show (f Int)) => Property
applicative_homomorphism = property do
  x <- forAll (Gen.int (Range.linear 0 10))
  y <- forAll (Gen.int (Range.linear 0 10))

  (pure (+) <*> pure x <*> pure y)
    === pure @f (x + y)

applicative_interchange :: (Applicative f, Eq (f Int), Show (f Int)) => Gen (f Int) -> Property
applicative_interchange gen = property do
  x <- forAll (Gen.int (Range.linear 0 10))
  y <- forAll gen

  let f = fmap (+) y
  (f <*> pure x) === (pure ($ x) <*> f)