-- |
-- Module      : Data.Functor.Combinator.Unsafe
  Copyright    : ( c )   2019
-- License     : BSD3
--
  Maintainer   : 
-- Stability   : experimental
-- Portability : non-portable
--
-- Working with non-standard typeclasses like 'Plus', 'Apply', 'Bind', and
-- 'Pointed' will sometimes cause problems when using with libraries that
-- do not provide instances, even though their types already are instances
-- of 'Alternative' or 'Applicative' or 'Monad'.
--
-- This module provides unsafe methods to "promote" 'Applicative' instances
-- to 'Apply', 'Alternative' to 'Plus', etc.
--
-- They are unsafe in the sense that if those types /already/ have those
-- instances, this will cause overlapping instances errors or problems with
-- coherence.  Because of this, you should always use these with /specific/
  @f@s , and never in a polymorphic way over @f@.
module Data.Functor.Combinator.Unsafe (
    unsafePlus
  , unsafeApply
  , unsafeBind
  , unsafePointed
  , unsafeConclude
  , unsafeDivise
  , unsafeInvariantCo
  , unsafeInvariantContra
  , unsafeInplyCo
  , unsafeInplyContra
  , unsafeInplicativeCo
  , unsafeInplicativeContra
  ) where

import           Control.Applicative
import           Data.Constraint
import           Data.Constraint.Unsafe
import           Data.Functor.Bind
import           Data.Functor.Contravariant
import           Data.Functor.Contravariant.Conclude
import           Data.Functor.Contravariant.Divise
import           Data.Functor.Contravariant.Divisible
import           Data.Functor.Invariant
import           Data.Functor.Invariant.Inplicative
import           Data.Functor.Plus
import           Data.Pointed

-- | For any @'Alternative' f@, produce a value that would require @'Plus'
-- f@.
--
  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has a ' Plus ' instance .
--
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
unsafePlus :: forall f proxy r. Alternative f => proxy f -> (Plus f => r) -> r
unsafePlus _ x = case unsafeCoerceConstraint @(Plus (WrappedApplicative f)) @(Plus f) of
    Sub Dict -> x

-- | For any @'Applicative' f@, produce a value that would require @'Apply'
-- f@.
--
  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has a ' Apply ' instance .
--
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
unsafeApply :: forall f proxy r. Applicative f => proxy f -> (Apply f => r) -> r
unsafeApply _ x = case unsafeCoerceConstraint @(Apply (WrappedApplicative f)) @(Apply f) of
    Sub Dict -> x

-- | For any @'Monad' f@, produce a value that would require @'Bind'
-- f@.
--
  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has a ' Bind ' instance .
--
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
unsafeBind :: forall f proxy r. Monad f => proxy f -> (Bind f => r) -> r
unsafeBind _ x = case unsafeCoerceConstraint @(Bind (WrappedMonad f)) @(Bind f) of
    Sub Dict -> x

newtype PointMe f a = PointMe (f a)

instance Applicative f => Pointed (PointMe f) where
    point = PointMe . pure

-- | For any @'Applicative' f@, produce a value that would require
-- @'Pointed' f@.
--
  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has a ' Pointed ' instance .
--
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
unsafePointed :: forall f proxy r. Applicative f => proxy f -> (Pointed f => r) -> r
unsafePointed _ x = case unsafeCoerceConstraint @(Pointed (PointMe f)) @(Pointed f) of
    Sub Dict -> x

-- | For any @'Decidable' f@, produce a value that would require @'Conclude'
-- f@.
--
  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has a ' Conclude ' instance .
--
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
--
  @since 0.3.0.0
unsafeConclude :: forall f proxy r. Decidable f => proxy f -> (Conclude f => r) -> r
unsafeConclude _ x = case unsafeCoerceConstraint @(Conclude (WrappedDivisible f)) @(Conclude f) of
    Sub Dict -> x

-- | For any @'Divisible' f@, produce a value that would require @'Divise'
-- f@.
--
  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has a ' Divise ' instance .
--
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
--
  @since 0.3.0.0
unsafeDivise :: forall f proxy r. Divisible f => proxy f -> (Divise f => r) -> r
unsafeDivise _ x = case unsafeCoerceConstraint @(Divise (WrappedDivisible f)) @(Divise f) of
    Sub Dict -> x

-- | For any @'Functor' f@, produce a value that would require @'Invariant'
-- f@.
--
  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has an ' Invariant ' instance .
--
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
--
  @since 
unsafeInvariantCo :: forall f proxy r. Functor f => proxy f -> (Invariant f => r) -> r
unsafeInvariantCo _ x = case unsafeCoerceConstraint @(Invariant (WrappedFunctor f)) @(Invariant f) of
    Sub Dict -> x

-- | For any @'Contravariant' f@, produce a value that would require @'Invariant'
-- f@.
--
  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has an ' Invariant ' instance .
--
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
--
  @since 
unsafeInvariantContra :: forall f proxy r. Contravariant f => proxy f -> (Invariant f => r) -> r
unsafeInvariantContra _ x = case unsafeCoerceConstraint @(Invariant (WrappedContravariant f)) @(Invariant f) of
    Sub Dict -> x

-- | For any @'Apply' f@, produce a value that would require @'Inply'
-- f@.
--
  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has an ' Inply ' instance .
--
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
--
  @since 
unsafeInplyCo :: forall f proxy r. Apply f => proxy f -> (Inply f => r) -> r
unsafeInplyCo _ x = case unsafeCoerceConstraint @(Inply (WrappedFunctor f)) @(Inply f) of
    Sub Dict -> x

-- | For any @'Divise' f@, produce a value that would require @'Inply'
-- f@.
--
  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has an ' Inply ' instance .
--
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
--
  @since 
unsafeInplyContra :: forall f proxy r. Divise f => proxy f -> (Inply f => r) -> r
unsafeInplyContra _ x = case unsafeCoerceConstraint @(Inply (WrappedContravariant f)) @(Inply f) of
    Sub Dict -> x

-- | For any @'Applicative' f@, produce a value that would require
-- @'Inplicative' f@.
--
  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has an ' Inplicative ' instance .
--
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
--
  @since 
unsafeInplicativeCo :: forall f proxy r. (Applicative f, Invariant f) => proxy f -> (Inplicative f => r) -> r
unsafeInplicativeCo _ x = case unsafeCoerceConstraint @(Inply (WrappedApplicativeOnly f)) @(Inplicative f) of
    Sub Dict -> x

-- | For any @'Divisibl3' f@, produce a value that would require
-- @'Inplicative' f@.
--
  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has an ' Inplicative ' instance .
--
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
--
  @since 
unsafeInplicativeContra :: forall f proxy r. (Divisible f, Invariant f) => proxy f -> (Inplicative f => r) -> r
unsafeInplicativeContra _ x = case unsafeCoerceConstraint @(Inply (WrappedDivisibleOnly f)) @(Inplicative f) of
    Sub Dict -> x


 |
 Module      : Data.Functor.Combinator.Unsafe
 License     : BSD3

 Stability   : experimental
 Portability : non-portable

 Working with non-standard typeclasses like 'Plus', 'Apply', 'Bind', and
 'Pointed' will sometimes cause problems when using with libraries that
 do not provide instances, even though their types already are instances
 of 'Alternative' or 'Applicative' or 'Monad'.

 This module provides unsafe methods to "promote" 'Applicative' instances
 to 'Apply', 'Alternative' to 'Plus', etc.

 They are unsafe in the sense that if those types /already/ have those
 instances, this will cause overlapping instances errors or problems with
 coherence.  Because of this, you should always use these with /specific/
 | For any @'Alternative' f@, produce a value that would require @'Plus'
 f@.


 | For any @'Applicative' f@, produce a value that would require @'Apply'
 f@.


 | For any @'Monad' f@, produce a value that would require @'Bind'
 f@.


 | For any @'Applicative' f@, produce a value that would require
 @'Pointed' f@.


 | For any @'Decidable' f@, produce a value that would require @'Conclude'
 f@.



 | For any @'Divisible' f@, produce a value that would require @'Divise'
 f@.



 | For any @'Functor' f@, produce a value that would require @'Invariant'
 f@.



 | For any @'Contravariant' f@, produce a value that would require @'Invariant'
 f@.



 | For any @'Apply' f@, produce a value that would require @'Inply'
 f@.



 | For any @'Divise' f@, produce a value that would require @'Inply'
 f@.



 | For any @'Applicative' f@, produce a value that would require
 @'Inplicative' f@.



 | For any @'Divisibl3' f@, produce a value that would require
 @'Inplicative' f@.



  Copyright    : ( c )   2019
  Maintainer   : 
  @f@s , and never in a polymorphic way over @f@.
module Data.Functor.Combinator.Unsafe (
    unsafePlus
  , unsafeApply
  , unsafeBind
  , unsafePointed
  , unsafeConclude
  , unsafeDivise
  , unsafeInvariantCo
  , unsafeInvariantContra
  , unsafeInplyCo
  , unsafeInplyContra
  , unsafeInplicativeCo
  , unsafeInplicativeContra
  ) where

import           Control.Applicative
import           Data.Constraint
import           Data.Constraint.Unsafe
import           Data.Functor.Bind
import           Data.Functor.Contravariant
import           Data.Functor.Contravariant.Conclude
import           Data.Functor.Contravariant.Divise
import           Data.Functor.Contravariant.Divisible
import           Data.Functor.Invariant
import           Data.Functor.Invariant.Inplicative
import           Data.Functor.Plus
import           Data.Pointed

  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has a ' Plus ' instance .
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
unsafePlus :: forall f proxy r. Alternative f => proxy f -> (Plus f => r) -> r
unsafePlus _ x = case unsafeCoerceConstraint @(Plus (WrappedApplicative f)) @(Plus f) of
    Sub Dict -> x

  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has a ' Apply ' instance .
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
unsafeApply :: forall f proxy r. Applicative f => proxy f -> (Apply f => r) -> r
unsafeApply _ x = case unsafeCoerceConstraint @(Apply (WrappedApplicative f)) @(Apply f) of
    Sub Dict -> x

  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has a ' Bind ' instance .
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
unsafeBind :: forall f proxy r. Monad f => proxy f -> (Bind f => r) -> r
unsafeBind _ x = case unsafeCoerceConstraint @(Bind (WrappedMonad f)) @(Bind f) of
    Sub Dict -> x

newtype PointMe f a = PointMe (f a)

instance Applicative f => Pointed (PointMe f) where
    point = PointMe . pure

  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has a ' Pointed ' instance .
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
unsafePointed :: forall f proxy r. Applicative f => proxy f -> (Pointed f => r) -> r
unsafePointed _ x = case unsafeCoerceConstraint @(Pointed (PointMe f)) @(Pointed f) of
    Sub Dict -> x

  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has a ' Conclude ' instance .
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
  @since 0.3.0.0
unsafeConclude :: forall f proxy r. Decidable f => proxy f -> (Conclude f => r) -> r
unsafeConclude _ x = case unsafeCoerceConstraint @(Conclude (WrappedDivisible f)) @(Conclude f) of
    Sub Dict -> x

  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has a ' Divise ' instance .
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
  @since 0.3.0.0
unsafeDivise :: forall f proxy r. Divisible f => proxy f -> (Divise f => r) -> r
unsafeDivise _ x = case unsafeCoerceConstraint @(Divise (WrappedDivisible f)) @(Divise f) of
    Sub Dict -> x

  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has an ' Invariant ' instance .
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
  @since 
unsafeInvariantCo :: forall f proxy r. Functor f => proxy f -> (Invariant f => r) -> r
unsafeInvariantCo _ x = case unsafeCoerceConstraint @(Invariant (WrappedFunctor f)) @(Invariant f) of
    Sub Dict -> x

  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has an ' Invariant ' instance .
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
  @since 
unsafeInvariantContra :: forall f proxy r. Contravariant f => proxy f -> (Invariant f => r) -> r
unsafeInvariantContra _ x = case unsafeCoerceConstraint @(Invariant (WrappedContravariant f)) @(Invariant f) of
    Sub Dict -> x

  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has an ' Inply ' instance .
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
  @since 
unsafeInplyCo :: forall f proxy r. Apply f => proxy f -> (Inply f => r) -> r
unsafeInplyCo _ x = case unsafeCoerceConstraint @(Inply (WrappedFunctor f)) @(Inply f) of
    Sub Dict -> x

  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has an ' Inply ' instance .
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
  @since 
unsafeInplyContra :: forall f proxy r. Divise f => proxy f -> (Inply f => r) -> r
unsafeInplyContra _ x = case unsafeCoerceConstraint @(Inply (WrappedContravariant f)) @(Inply f) of
    Sub Dict -> x

  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has an ' Inplicative ' instance .
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
  @since 
unsafeInplicativeCo :: forall f proxy r. (Applicative f, Invariant f) => proxy f -> (Inplicative f => r) -> r
unsafeInplicativeCo _ x = case unsafeCoerceConstraint @(Inply (WrappedApplicativeOnly f)) @(Inplicative f) of
    Sub Dict -> x

  Always use with concrete and specific @f@ only , and never use with any
  @f@ that already has an ' Inplicative ' instance .
  The ' Data . Proxy . Proxy ' argument allows you to specify which specific @f@
  you want to enhance .   You can pass in something like  . Proxy . Proxy '
  \@MyFunctor@.
  @since 
unsafeInplicativeContra :: forall f proxy r. (Divisible f, Invariant f) => proxy f -> (Inplicative f => r) -> r
unsafeInplicativeContra _ x = case unsafeCoerceConstraint @(Inply (WrappedDivisibleOnly f)) @(Inplicative f) of
    Sub Dict -> x

