grisette-0.11.0.0: src/Grisette/Internal/Unified/Util.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
{-# HLINT ignore "Eta reduce" #-}
-- |
-- Module : Grisette.Internal.Unified.Util
-- Copyright : (c) Sirui Lu 2024
-- License : BSD-3-Clause (see the LICENSE file)
--
-- Maintainer : siruilu@cs.washington.edu
-- Stability : Experimental
-- Portability : GHC only
module Grisette.Internal.Unified.Util
( DecideEvalMode (..),
withMode,
EvalModeConvertible (..),
)
where
import Data.Typeable (type (:~:) (Refl))
import Grisette.Internal.Unified.EvalModeTag (EvalModeTag (C, S))
import Grisette.Internal.Utils.Parameterized (unsafeAxiom)
-- | A class that provides the mode tag at runtime.
class DecideEvalMode (mode :: EvalModeTag) where
decideEvalMode :: EvalModeTag
instance DecideEvalMode 'C where
decideEvalMode = C
{-# INLINE decideEvalMode #-}
instance DecideEvalMode 'S where
decideEvalMode = S
{-# INLINE decideEvalMode #-}
-- | Case analysis on the mode.
withMode ::
forall mode r.
(DecideEvalMode mode) =>
((mode ~ 'C) => r) ->
((mode ~ 'S) => r) ->
r
withMode con sym =
case decideEvalMode @mode of
C -> case unsafeAxiom @mode @'C of
Refl -> con
S -> case unsafeAxiom @mode @'S of
Refl -> sym
{-# INLINE withMode #-}
-- | A class saying that we can convert a value with one mode to another mode.
--
-- Allowed conversions:
--
-- - 'C' <-> 'C'
-- - 'S' <-> 'S'
-- - 'C' <-> 'S'
--
-- Conversion from left to right uses 'Grisette.ToSym' class, and conversion
-- from right to left uses 'Grisette.ToCon' class.
class
(DecideEvalMode c, DecideEvalMode s) =>
EvalModeConvertible (c :: EvalModeTag) (s :: EvalModeTag)
where
withModeConvertible ::
((c ~ 'C) => r) ->
((s ~ 'S) => r) ->
r
withModeConvertible' ::
((c ~ 'C, s ~ 'C) => r) ->
((c ~ 'C, s ~ 'S) => r) ->
((c ~ 'S, s ~ 'S) => r) ->
r
instance {-# INCOHERENT #-} (DecideEvalMode s) => EvalModeConvertible 'C s where
withModeConvertible con _ = con
{-# INLINE withModeConvertible #-}
withModeConvertible' con0 con1 _ = withMode @s con0 con1
{-# INLINE withModeConvertible' #-}
instance {-# INCOHERENT #-} (DecideEvalMode c) => EvalModeConvertible c 'S where
withModeConvertible _ sym = sym
{-# INLINE withModeConvertible #-}
withModeConvertible' _ sym0 sym1 = withMode @c sym0 sym1
{-# INLINE withModeConvertible' #-}