packages feed

hypertypes-0.2.2: src/Hyper/Unify/Binding.hs

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE UndecidableInstances #-}

-- | A pure data structures implementation of unification variables state
module Hyper.Unify.Binding
    ( UVar (..)
    , _UVar
    , Binding (..)
    , _Binding
    , emptyBinding
    , bindingDict
    ) where

import Control.Lens (ALens')
import qualified Control.Lens as Lens
import Control.Monad.State (MonadState (..))
import Data.Sequence (Seq)
import Hyper.Class.Unify (BindingDict (..))
import Hyper.Type (AHyperType, type (#))
import Hyper.Unify.Term

import Hyper.Internal.Prelude

-- | A unification variable identifier pure state based unification
newtype UVar (t :: AHyperType) = UVar Int
    deriving stock (Generic, Show)
    deriving newtype (Eq, Ord)

makePrisms ''UVar

-- | The state of unification variables implemented in a pure data structure
newtype Binding t = Binding (Seq (UTerm UVar t))
    deriving stock (Generic)

makePrisms ''Binding
makeCommonInstances [''Binding]

-- | An empty 'Binding'
emptyBinding :: Binding t
emptyBinding = Binding mempty

-- | A 'BindingDict' for 'UVar's in a 'MonadState' whose state contains a 'Binding'
{-# INLINE bindingDict #-}
bindingDict ::
    MonadState s m =>
    ALens' s (Binding # t) ->
    BindingDict UVar m t
bindingDict l =
    BindingDict
        { lookupVar =
            \(UVar h) ->
                Lens.use (Lens.cloneLens l . _Binding)
                    <&> (^?! Lens.ix h)
        , newVar =
            \x ->
                Lens.cloneLens l . _Binding <<%= (Lens.|> x)
                    <&> UVar . length
        , bindVar =
            \(UVar h) ->
                (Lens.cloneLens l . _Binding . Lens.ix h .=)
        }