{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE TypeOperators #-}

-- |
-- Module      :   Grisette.Internal.Unified.UnifiedAlgReal
-- 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.UnifiedAlgReal
  ( UnifiedAlgReal,
    GetAlgReal,
  )
where

import Control.Exception (ArithException)
import Control.Monad.Error.Class (MonadError)
import Grisette.Internal.Core.Data.Class.SafeFdiv (FdivOr)
import Grisette.Internal.SymPrim.AlgReal (AlgReal)
import Grisette.Internal.SymPrim.SymAlgReal (SymAlgReal)
import Grisette.Internal.SymPrim.SymPrim (Prim)
import Grisette.Internal.Unified.Class.UnifiedFromIntegral (UnifiedFromIntegral)
import Grisette.Internal.Unified.Class.UnifiedRep
  ( UnifiedConRep (ConType),
    UnifiedSymRep (SymType),
  )
import Grisette.Internal.Unified.Class.UnifiedSafeFdiv (UnifiedSafeFdiv)
import Grisette.Internal.Unified.Class.UnifiedSimpleMergeable (UnifiedBranching)
import Grisette.Internal.Unified.EvalModeTag (EvalModeTag (C, S))
import Grisette.Internal.Unified.UnifiedInteger (GetInteger)
import Grisette.Internal.Unified.UnifiedPrim (UnifiedBasicPrim)

class
  ( r ~ GetAlgReal mode,
    UnifiedConRep r,
    UnifiedSymRep r,
    ConType r ~ AlgReal,
    SymType r ~ SymAlgReal,
    UnifiedBasicPrim mode r,
    Prim r,
    Num r,
    Fractional r,
    FdivOr r,
    forall m.
    (UnifiedBranching mode m, MonadError ArithException m) =>
    UnifiedSafeFdiv mode ArithException r m,
    UnifiedFromIntegral mode (GetInteger mode) r
  ) =>
  UnifiedAlgRealImpl (mode :: EvalModeTag) r
    | mode -> r
  where
  -- | Get a unified algebraic real type. Resolves to 'AlgReal' in 'C' mode,
  -- and 'SymAlgReal' in 'S' mode.
  --
  -- 'Floating', 'Grisette.LogBaseOr' and 'Grisette.SafeLogBase' for
  -- 'SymAlgReal' are not provided as they are not available for 'AlgReal'.
  type GetAlgReal mode = real | real -> mode

instance UnifiedAlgRealImpl 'C AlgReal where
  type GetAlgReal 'C = AlgReal

instance UnifiedAlgRealImpl 'S SymAlgReal where
  type GetAlgReal 'S = SymAlgReal

-- | Evaluation mode with unified 'AlgReal' type.
class
  (UnifiedAlgRealImpl mode (GetAlgReal mode)) =>
  UnifiedAlgReal (mode :: EvalModeTag)

instance UnifiedAlgReal 'C

instance UnifiedAlgReal 'S