{-# LANGUAGE ConstraintKinds       #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE KindSignatures        #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableInstances  #-}

module Data.Constraint.Emerge
  ( Emerge
  , emerge
  , Dict (..)
  ) where

import Data.Constraint


------------------------------------------------------------------------------
-- | Typeclass asserting we can determine the existence of the constraint 'c'
-- at runtime.
class Emerge (c :: Constraint) where
  emerge' :: Maybe (Dict c)


------------------------------------------------------------------------------
-- | Get a dictionary for 'c' if it exists.
emerge :: Emerge c => Maybe (Dict c)
emerge = emerge'


------------------------------------------------------------------------------
-- | A typeclass whose dictionaries we can coerce into those for 'Emerge' if
-- our constraint wasn't satisfied.
class AlwaysFail where
  alwaysFail :: Maybe (Dict a)

instance AlwaysFail where
  alwaysFail = Nothing


------------------------------------------------------------------------------
-- | A typeclass whose dictionaries we can coerce into those for 'Emerge' if
-- our constraint was satisfied.
class Succeed (a :: Constraint) where
  succeed :: Maybe (Dict a)

instance c => Succeed c where
  succeed = Just Dict