packages feed

grisette-0.12.0.0: src/Grisette/Internal/SymPrim/Prim/SomeTerm.hs

{-# LANGUAGE ExplicitNamespaces #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

-- |
-- Module      :   Grisette.Internal.SymPrim.Prim.SomeTerm
-- Copyright   :   (c) Sirui Lu 2021-2024
-- License     :   BSD-3-Clause (see the LICENSE file)
--
-- Maintainer  :   siruilu@cs.washington.edu
-- Stability   :   Experimental
-- Portability :   GHC only
module Grisette.Internal.SymPrim.Prim.SomeTerm
  ( SomeTerm (..),
    someTerm,
    someTermId,
  )
where

import Data.Hashable (Hashable (hashWithSalt))
import Data.Typeable (eqT, type (:~:) (Refl))
import Grisette.Internal.SymPrim.Prim.Internal.Caches (Id)
import Grisette.Internal.SymPrim.Prim.Internal.Term
  ( SupportedPrim (primTypeRep),
    Term,
    termId,
    pattern SupportedTerm,
  )

-- | Existential wrapper for symbolic Grisette terms.
data SomeTerm where
  SomeTerm :: forall a. (SupportedPrim a) => Term a -> SomeTerm

instance Eq SomeTerm where
  (SomeTerm (t1 :: Term a)) == (SomeTerm (t2 :: Term b)) =
    case eqT @a @b of
      Just Refl -> t1 == t2
      Nothing -> False

instance Hashable SomeTerm where
  hashWithSalt s (SomeTerm t) = hashWithSalt s t

instance Show SomeTerm where
  show (SomeTerm (t :: Term a)) =
    "<<" ++ show t ++ " :: " ++ show (primTypeRep @a) ++ ">>"

-- | Wrap a symbolic term into t'SomeTerm'.
someTerm :: Term a -> SomeTerm
someTerm v@SupportedTerm = SomeTerm v
{-# INLINE someTerm #-}

-- | Get the unique identifier of a symbolic term.
someTermId :: SomeTerm -> Id
someTermId (SomeTerm t) = termId t
{-# INLINE someTermId #-}