{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE ImplicitParams #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE Trustworthy #-} {-# LANGUAGE TypeInType #-} -- | Functions for debugging. If you left these functions in your code -- then warning is generated to remind you about left usages. Also, some -- functions (and data types) are convenient for prototyping. module Universum.Debug ( Undefined (..) , error , trace , traceM , traceId , traceIdWith , traceShow , traceShowId , traceShowIdWith , traceShowM , undefined ) where import Control.Monad (Monad, return) import Data.Data (Data) import Data.Text (Text, pack, unpack) import GHC.Generics (Generic) import System.IO.Unsafe (unsafePerformIO) import GHC.Exception (errorCallWithCallStackException) import GHC.Exts (RuntimeRep, TYPE, raise#) import Universum.Applicative (pass) import Universum.Base (HasCallStack, callStack) import Universum.Print (putStrLn) import qualified Prelude as P -- | Version of 'Debug.Trace.trace' that leaves a warning and takes 'Text'. {-# WARNING trace "'trace' remains in code" #-} trace :: Text -> a -> a trace string expr = unsafePerformIO (do putStrLn string return expr) -- | 'P.error' that takes 'Text' as an argument. error :: forall (r :: RuntimeRep) . forall (a :: TYPE r) . HasCallStack => Text -> a error s = raise# (errorCallWithCallStackException (unpack s) callStack) -- | Version of 'Debug.Trace.traceShow' that leaves a warning. {-# WARNING traceShow "'traceShow' remains in code" #-} traceShow :: P.Show a => a -> b -> b traceShow a b = trace (pack (P.show a)) b -- | Version of 'Debug.Trace.traceShowId' that leaves a warning. {-# WARNING traceShowId "'traceShowId' remains in code" #-} traceShowId :: P.Show a => a -> a traceShowId a = trace (pack (P.show a)) a {- | Version of 'Debug.Trace.traceId' that leaves a warning. Useful to tag printed data, for instance: @ traceIdWith (\x -> "My data: " <> show x) (veryLargeExpression) @ This is especially useful with custom formatters: @ traceIdWith (\x -> "My data: " <> pretty x) (veryLargeExpression) @ -} {-# WARNING traceIdWith "'traceIdWith' remains in code" #-} traceIdWith :: (a -> Text) -> a -> a traceIdWith f a = trace (f a) a -- | Version of 'Debug.Trace.traceShowId' that leaves a warning. -- Useful to tag printed data, for instance: -- -- @ -- traceShowIdWith ("My data: ", ) (veryLargeExpression) -- @ {-# WARNING traceShowIdWith "'traceShowIdWith' remains in code" #-} traceShowIdWith :: P.Show s => (a -> s) -> a -> a traceShowIdWith f a = trace (pack (P.show (f a))) a -- | Version of 'Debug.Trace.traceShowM' that leaves a warning. {-# WARNING traceShowM "'traceShowM' remains in code" #-} traceShowM :: (P.Show a, Monad m) => a -> m () traceShowM a = trace (pack (P.show a)) pass -- | Version of 'Debug.Trace.traceM' that leaves a warning and takes 'Text'. {-# WARNING traceM "'traceM' remains in code" #-} traceM :: (Monad m) => Text -> m () traceM s = trace s pass -- | Version of 'Debug.Trace.traceId' that leaves a warning. {-# WARNING traceId "'traceId' remains in code" #-} traceId :: Text -> Text traceId s = trace s s -- | Similar to 'undefined' but data type. {-# WARNING Undefined "'Undefined' type remains in code" #-} data Undefined = Undefined deriving stock (P.Eq, P.Ord, P.Show, P.Read, P.Enum, P.Bounded, Data, Generic) -- | 'P.undefined' that leaves a warning in code on every usage. {-# WARNING undefined "'undefined' function remains in code (or use 'error')" #-} undefined :: forall (r :: RuntimeRep) . forall (a :: TYPE r) . HasCallStack => a undefined = P.undefined