{-# LANGUAGE AllowAmbiguousTypes #-} -- joinA
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ImpredicativeTypes #-}
{-|

Like 'Data.Equality.Analysis' but for 'Analysis' that are only well-defined
within an (effectful) context. Mostly used with the monadic operations
'representM', 'addM', 'mergeM', and 'rebuildM'.

This effectful 'Analysis' could almost be trivially defined in terms of the
other, through a "contextful" domain and by means of the '_classes' 'Traversal'.

However, that would require an instance of 'Eq' for the monadic domain, which
is usually unnattainable.

Therefore, we do need this class for monadic 'Analysis'.

-}
module Data.Equality.Analysis.Monadic where


import Data.Kind (Type)

import Data.Equality.Graph.Internal (EGraph)
import Data.Equality.Graph.Classes

-- | An e-class analysis with domain @domain@ defined for a language @l@, whose operations are only well-defined within some effectful context.
--
-- The @domain@ is the type of the domain of the e-class analysis, that is, the
-- type of the data stored in an e-class according to this e-class analysis
class (Monad m, Eq domain) => AnalysisM m domain (l :: Type -> Type) where

    -- | When a new e-node is added into a new, singleton e-class, construct a
    -- new value of the domain to be associated with the new e-class, by
    -- accessing the associated data of the node's children
    --
    -- The argument is the e-node term populated with its children data
    makeA :: l domain -> m domain

    -- | When e-classes c1 c2 are being merged into c, join d_c1 and
    -- d_c2 into a new value d_c to be associated with the new
    -- e-class c
    joinA :: domain -> domain -> m domain

    -- | Optionally modify the e-class c (based on d_c), typically by adding an
    -- e-node to c. Modify should be idempotent if no other changes occur to
    -- the e-class, i.e., modify(modify(c)) = modify(c)
    modifyA :: ClassId
            -- ^ Id of class @c@ whose new data @d_c@ triggered the modify call
            -> EGraph domain l
            -- ^ E-graph where class @c@ being modified exists
            -> m (EGraph domain l)
            -- ^ E-graph resulting from the modification
    modifyA ClassId
_ = EGraph domain l -> m (EGraph domain l)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    {-# INLINE modifyA #-}


-- | The simplest analysis that defines the domain to be () and does nothing otherwise
instance Monad m => AnalysisM m () l where
  makeA :: l () -> m ()
makeA l ()
_ = () -> m ()
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
  joinA :: () -> () -> m ()
joinA ()
_ ()
_ = () -> m ()
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()