module Blanks.Sub
  ( SubError (..)
  , ThrowSub (..)
  , rethrowSub
  ) where

import Control.Exception (Exception, throwIO)

-- | Errors that happen in the course of instantiation, thrown by 'blankApply'
-- and related functions.
data SubError
  = ApplyError !Int !Int
  | UnboundError !Int
  | NonBinderError
  deriving (Eq, Show)

instance Exception SubError

-- | Some monadic context that lets you throw a 'SubError'.
-- Exists to let you rethrow to a more convenient context rather than
-- pattern maching.
class ThrowSub m where
  throwSub :: SubError -> m a

rethrowSub :: (Applicative m, ThrowSub m) => Either SubError a -> m a
rethrowSub = either throwSub pure

instance ThrowSub (Either SubError) where
  throwSub = Left

instance ThrowSub IO where
  throwSub = throwIO