{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

module Test.Monad.Reader where

import Control.Monad.Reader
import Test.QuickCheck.HigherOrder (Equation(..))

-- * Primary laws

ask_ask
  :: forall m r
  .  MonadReader r m
  => Equation (m r)
ask_ask = (ask >> ask) :=: ask @r @m

local_ask
  :: forall m r
  .  MonadReader r m
  => (r -> r) -> Equation (m r)
local_ask f = local f ask :=: fmap @m f ask

-- Also:
-- - 'local' and 'reader' should be monad homomorphisms.
-- - 'ask' should have no effect.

-- * Secondary laws

local_local
  :: forall m a r
  .  MonadReader r m
  => (r -> r) -> (r -> r) -> m a -> Equation (m a)
local_local f g m = local f (local g m) :=: local (g . f) m

local_id
  :: forall m a r
  .  MonadReader r m
  => m a -> Equation (m a)
local_id m = local id m :=: m