-- Ensure that rewrites work with polymorphic types

{-# LANGUAGE Rank2Types #-}

{-@ LIQUID "--extensionality" @-}
{-@ LIQUID "--reflection" @-}
{-@ LIQUID "--ple" @-}
{-@ LIQUID "--prune-unsorted" @-}
module ReWrite2 where

data OurMonad m = OurMonad {
  bind :: forall a b. m a -> (a -> m b) -> m b,
  return :: forall a.   a -> m a
}

{-@
data OurMonad m = OurMonad {
  bind   :: forall a b. m a -> (a -> m b) -> m b,
  return :: forall a.   a -> m a
}
@-}

{-@ reflect kleisli @-}
{-@ kleisli :: om : OurMonad m
            ->  f : (a -> m b)
            ->  g : (b -> m c)
            ->  x : a
            -> {v : m c | v = kleisli om f g x} @-}
kleisli :: OurMonad m -> (a -> m b) -> (b -> m c) -> a -> m c
kleisli om f g x = bind om (f x) g

{-@ kp :: om : OurMonad m
            ->  f : (a -> m b)
            ->  g : (b -> m c)
            ->  x : a
            -> {v : () | kleisli om f g x = bind om (f x) g} @-}
kp :: OurMonad m -> (a -> m b) -> (b -> m c) -> a -> ()
kp om f g x = ()

{-@ reflect lhs @-}
lhs om f g x = kleisli om f g x

{-@ reflect rhs @-}
rhs om f g x = bind om (f x) g

{-@ rewriteWith mp [kp] @-}
{-@ mp :: om : OurMonad m
            ->  f : (a -> m b)
            ->  g : (b -> m c)
            ->  x : a
            -> { lhs om f g x = rhs om f g x } @-}
mp :: OurMonad m -> (a -> m b) -> (b -> m c) -> a -> ()
mp om f g x = ()
