packages feed

knit-haskell-0.8.0.0: src/Knit/Report/Error.hs

{-# LANGUAGE ConstraintKinds      #-}
{-# LANGUAGE DataKinds            #-}
{-# LANGUAGE ExtendedDefaultRules #-}
{-# LANGUAGE FlexibleContexts     #-}
{-# LANGUAGE GADTs                #-}
{-# LANGUAGE OverloadedStrings     #-}
{-# LANGUAGE PolyKinds            #-}
{-# LANGUAGE Rank2Types           #-}
{-# LANGUAGE ScopedTypeVariables  #-}
{-# LANGUAGE TypeOperators        #-}
{-# LANGUAGE TypeApplications     #-}
{-# LANGUAGE TypeFamilies         #-}
{-# LANGUAGE UndecidableInstances #-}
{-|
Module      : Knit.Report.Error
Description : knit-haskell functions to handle and raise errors in knit-haskell reports.
Copyright   : (c) Adam Conner-Sax 2019
License     : BSD-3-Clause
Maintainer  : adam_conner_sax@yahoo.com
Stability   : experimental

This module has various combinators for simplifying the throwing of Errors in knit-haskell.

<https://github.com/adamConnerSax/knit-haskell/tree/master/examples Examples> are available, and might be useful for seeing how all this works.

-}
module Knit.Report.Error
  (
    -- * Error combinators
    knitError
  , knitMaybe
  , knitEither
  , knitMapError
  )
where

import qualified Knit.Report.EffectStack       as K
import qualified Text.Pandoc.Error             as PA
import           Knit.Effect.PandocMonad        ( textToPandocText )

import qualified Data.Text                     as T

import qualified Polysemy                      as P
import qualified Polysemy.Error                as PE



-- | Throw an error with a specific message.  This will emerge as a 'PandocSomeError' in order
-- to avoid complicating the error type.
-- NB: The Member constraint is satisfied by KnitEffectStack m.
knitError :: P.Member (PE.Error PA.PandocError) r => T.Text -> P.Sem r a
knitError msg =
  PE.throw (PA.PandocSomeError $ textToPandocText $ "Knit User Error: " <> msg)

-- | Throw on 'Nothing' with given message.  This will emerge as a 'PandocSomeError' in order
-- to avoid complicating the error type.
knitMaybe
  :: P.Member (PE.Error PA.PandocError) r => T.Text -> Maybe a -> P.Sem r a
knitMaybe msg = maybe (knitError msg) return

-- | Throw on 'Left' with message.  This will emerge as a 'PandocSomeError' in order
-- to avoid complicating the error type.
knitEither
  :: P.Member (PE.Error PA.PandocError) r => Either T.Text a -> P.Sem r a
knitEither = either knitError return

-- | Map an error type, @e, into a 'PandocError' so it will be handled in this stack
knitMapError
  :: forall e r a
   . K.KnitEffects r
  => (e -> T.Text)
  -> P.Sem (PE.Error e ': r) a
  -> P.Sem r a
knitMapError f = PE.mapError $ PA.PandocSomeError . textToPandocText . f