    {-# LANGUAGE CPP, NoImplicitPrelude #-}
    module Debug.Trace.Compat (
      module Base
    , traceId
    , traceShowId
    , traceM
    , traceShowM
    ) where

    #if !(MIN_VERSION_base(4,7,0)) || MIN_VERSION_base(4,9,0)
    import Debug.Trace as Base
    #else
    import Debug.Trace as Base hiding (
        traceM
      , traceShowM
      )
    #endif

    #if !(MIN_VERSION_base(4,9,0))
    import Prelude.Compat
    #endif

    #if !(MIN_VERSION_base(4,7,0))
    {-|
    Like 'trace' but returns the message instead of a third value.

    /Since: 4.7.0.0/
    -}
    traceId :: String -> String
    traceId a = trace a a

    {-|
    Like 'traceShow' but returns the shown value instead of a third value.

    /Since: 4.7.0.0/
    -}
    traceShowId :: (Show a) => a -> a
    traceShowId a = trace (show a) a
    #endif

    #if !(MIN_VERSION_base(4,9,0))
    {-|
    Like 'trace' but returning unit in an arbitrary 'Applicative' context. Allows
    for convenient use in do-notation.

    Note that the application of 'traceM' is not an action in the 'Applicative'
    context, as 'traceIO' is in the 'IO' type. While the fresh bindings in the
    following example will force the 'traceM' expressions to be reduced every time
    the @do@-block is executed, @traceM "not crashed"@ would only be reduced once,
    and the message would only be printed once.  If your monad is in 'MonadIO',
    @liftIO . traceIO@ may be a better option.

    > ... = do
    >   x <- ...
    >   traceM $ "x: " ++ show x
    >   y <- ...
    >   traceM $ "y: " ++ show y

    /Since: 4.7.0.0/
    -}
    traceM :: (Applicative f) => String -> f ()
    traceM string = trace string $ pure ()

    {-|
    Like 'traceM', but uses 'show' on the argument to convert it to a 'String'.

    > ... = do
    >   x <- ...
    >   traceShowM $ x
    >   y <- ...
    >   traceShowM $ x + y

    /Since: 4.7.0.0/
    -}
    traceShowM :: (Show a, Applicative f) => a -> f ()
    traceShowM = traceM . show
    #endif