{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs, DataKinds #-}
{-# LANGUAGE Safe #-}
-- | A Trace effect for debugging
module Control.Eff.Trace( Trace (..)
                        , withTrace
                        , trace
                        , runTrace
                        ) where

import Control.Eff
import Control.Eff.Extend
import Data.Function (fix)

-- | Trace effect for debugging
data Trace v where
  Trace :: String -> Trace ()

-- | Embed a pure value in Trace context
withTrace :: a -> IO a
withTrace = return

-- | Given a callback and request, respond to it
instance Handle Trace r a (IO k) where
  handle step q (Trace s) = putStrLn s >> step (q ^$ ())

-- | Print a string as a trace.
trace :: Member Trace r => String -> Eff r ()
trace = send . Trace

-- | Run a computation producing Traces.
-- The handler for IO request: a terminal handler
runTrace :: Eff '[Trace] w -> IO w
runTrace = fix step where
  step next = eff return
              (\q u -> case u of
                  U0 x -> handle next q x
                  _    -> error "Impossible: Nothing to relay!")