{-# LANGUAGE CPP #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE Unsafe #-}
#if __GLASGOW_HASKELL__ >= 800
{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
#endif
-----------------------------------------------------------------------------
-- |
-- Module      :  Data.Constraint.Unsafe
-- Copyright   :  (C) 2011-2015 Edward Kmett
-- License     :  BSD-style (see the file LICENSE)
--
-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
-- Stability   :  experimental
-- Portability :  non-portable
--
----------------------------------------------------------------------------
module Data.Constraint.Unsafe
  ( Coercible
  , unsafeCoerceConstraint
  , unsafeDerive
  , unsafeUnderive
  -- * Sugar
  , unsafeApplicative
  , unsafeAlternative
  ) where

import Control.Applicative
import Control.Monad
import Data.Coerce
import Data.Constraint
import Unsafe.Coerce

-- | Coerce a dictionary unsafely from one type to another
unsafeCoerceConstraint :: a :- b
unsafeCoerceConstraint :: forall (a :: Constraint) (b :: Constraint). a :- b
unsafeCoerceConstraint = (Any :- Any) -> a :- b
forall a b. a -> b
unsafeCoerce Any :- Any
forall (a :: Constraint). a :- a
refl

-- | Coerce a dictionary unsafely from one type to a newtype of that type
unsafeDerive :: Coercible n o => (o -> n) -> t o :- t n
unsafeDerive :: forall n o (t :: * -> Constraint).
Coercible n o =>
(o -> n) -> t o :- t n
unsafeDerive o -> n
_ = t o :- t n
forall (a :: Constraint) (b :: Constraint). a :- b
unsafeCoerceConstraint

-- | Coerce a dictionary unsafely from a newtype of a type to the base type
unsafeUnderive :: Coercible n o => (o -> n) -> t n :- t o
unsafeUnderive :: forall n o (t :: * -> Constraint).
Coercible n o =>
(o -> n) -> t n :- t o
unsafeUnderive o -> n
_ = t n :- t o
forall (a :: Constraint) (b :: Constraint). a :- b
unsafeCoerceConstraint


-- | Construct an Applicative instance from a Monad
unsafeApplicative :: forall m a. Monad m => (Applicative m => m a) -> m a
#if __GLASGOW_HASKELL__ < 710
unsafeApplicative m = m \\ trans (unsafeCoerceConstraint :: Applicative (WrappedMonad m) :- Applicative m) ins
#else
unsafeApplicative :: forall (m :: * -> *) a. Monad m => (Applicative m => m a) -> m a
unsafeApplicative Applicative m => m a
m = m a
Applicative m => m a
m
#endif

-- | Construct an Alternative instance from a MonadPlus
unsafeAlternative :: forall m a. MonadPlus m => (Alternative m => m a) -> m a
#if __GLASGOW_HASKELL__ < 710
unsafeAlternative m = m \\ trans (unsafeCoerceConstraint :: Alternative (WrappedMonad m) :- Alternative m) ins
#else
unsafeAlternative :: forall (m :: * -> *) a.
MonadPlus m =>
(Alternative m => m a) -> m a
unsafeAlternative Alternative m => m a
m = m a
Alternative m => m a
m
#endif