swarm-0.7.0.0: 2D resource gathering game with programmable robots
LicenseBSD-3-Clause
Safe HaskellNone
LanguageHaskell2010

Swarm.Effect.Unify.Fast

Description

unification, using a map as a lazy substitution, i.e. a manually-maintained "functional shared memory".

See Dijkstra, Middelkoop, & Swierstra, "Efficient Functional Unification and Substitution", Utrecht University tech report UU-CS-2008-027 (section 5) for the basic idea, and Peyton Jones et al, "Practical type inference for arbitrary-rank types" (pp. 74--75) for a correct implementation of unification via references.

Synopsis

Documentation

(@@) :: (Ord n, Substitutes n a a) => Subst n a -> Subst n a -> Subst n a Source #

Compose two substitutions. Applying s1 @@ s2 is the same as applying first s2, then s1; that is, semantically, composition of substitutions corresponds exactly to function composition when they are considered as functions on terms.

As one would expect, composition is associative and has idS as its identity.

Note that we do not apply s1 to all the values in s2, since the substitution is maintained lazily; we do not need to maintain the invariant that values in the mapping do not contain any of the keys. This makes composition much faster, at the cost of making application more complex.

class Substitutes n b a where Source #

Class of things supporting substitution. Substitutes n b a means that we can apply a substitution of type Subst n b to a value of type a, replacing all the free names of type n inside the a with values of type b, resulting in a new value of type a.

We also do a lazy occurs-check during substitution application, so we need the ability to throw a unification error.

Methods

subst :: forall (sig :: (Type -> Type) -> Type -> Type) m. Has (Throw UnificationError) sig m => Subst n b -> a -> m a Source #

Instances

Instances details
Substitutes IntVar UType UType Source #

We can perform substitution on terms built up as the free monad over a structure functor f.

Instance details

Defined in Swarm.Effect.Unify.Fast

Methods

subst :: forall (sig :: (Type -> Type) -> Type -> Type) m. Has (Throw UnificationError) sig m => Subst IntVar UType -> UType -> m UType Source #

newtype UnificationC (m :: Type -> Type) a Source #

Carrier type for unification: we maintain a current substitution, a counter for generating fresh unification variables, and can throw unification errors.

Instances

Instances details
MonadIO m => MonadIO (UnificationC m) Source # 
Instance details

Defined in Swarm.Effect.Unify.Fast

Methods

liftIO :: IO a -> UnificationC m a #

(Alternative m, Monad m) => Alternative (UnificationC m) Source # 
Instance details

Defined in Swarm.Effect.Unify.Fast

Methods

empty :: UnificationC m a #

(<|>) :: UnificationC m a -> UnificationC m a -> UnificationC m a #

some :: UnificationC m a -> UnificationC m [a] #

many :: UnificationC m a -> UnificationC m [a] #

Monad m => Applicative (UnificationC m) Source # 
Instance details

Defined in Swarm.Effect.Unify.Fast

Methods

pure :: a -> UnificationC m a #

(<*>) :: UnificationC m (a -> b) -> UnificationC m a -> UnificationC m b #

liftA2 :: (a -> b -> c) -> UnificationC m a -> UnificationC m b -> UnificationC m c #

(*>) :: UnificationC m a -> UnificationC m b -> UnificationC m b #

(<*) :: UnificationC m a -> UnificationC m b -> UnificationC m a #

Functor m => Functor (UnificationC m) Source # 
Instance details

Defined in Swarm.Effect.Unify.Fast

Methods

fmap :: (a -> b) -> UnificationC m a -> UnificationC m b #

(<$) :: a -> UnificationC m b -> UnificationC m a #

Monad m => Monad (UnificationC m) Source # 
Instance details

Defined in Swarm.Effect.Unify.Fast

Methods

(>>=) :: UnificationC m a -> (a -> UnificationC m b) -> UnificationC m b #

(>>) :: UnificationC m a -> UnificationC m b -> UnificationC m b #

return :: a -> UnificationC m a #

(Algebra sig m, Has (Reader TDCtx) sig m) => Algebra (Unification :+: sig) (UnificationC m) Source #

Implementation of the Unification effect in terms of the UnificationC carrier.

Instance details

Defined in Swarm.Effect.Unify.Fast

Methods

alg :: forall ctx (n :: Type -> Type) a. Functor ctx => Handler ctx n (UnificationC m) -> (Unification :+: sig) n a -> ctx () -> UnificationC m (ctx a) #

runUnification :: forall (sig :: (Type -> Type) -> Type -> Type) m a. (Algebra sig m, Has (Reader TDCtx) sig m) => UnificationC m a -> m (Either UnificationError a) Source #

Run a Unification effect via the UnificationC carrier. Note that we also require an ambient Reader TDCtx effect, so unification will be sure to pick up whatever type aliases happen to be in scope.

unify :: forall (sig :: (Type -> Type) -> Type -> Type) m. (Has (Throw UnificationError) sig m, Has (Reader TDCtx) sig m, Has (State (Subst IntVar UType)) sig m, Has (State (Set (UType, UType))) sig m) => UType -> UType -> m UType Source #

Unify two types, returning a unified type equal to both. Note that for efficiency we don't do an occurs check here, but instead lazily during substitution.

We keep track of a set of pairs of types we have seen; if we ever see a pair a second time we simply assume they are equal without recursing further. This constitutes a finite (coinductive) algorithm for doing unification on recursive types.

For example, suppose we wanted to unify rec s. Unit + Unit + s and rec t. Unit + t. These types are actually equal since their infinite unfoldings are both Unit + Unit + Unit + ... In practice we would proceed through the following recursive calls to unify:

    (rec s. Unit + Unit + s)                 =:= (rec t. Unit + t)
        { unfold the LHS }
    (Unit + Unit + (rec s. Unit + Unit + s)) =:= (rec t. Unit + t)
        { unfold the RHS }
    (Unit + Unit + (rec s. Unit + Unit + s)) =:= (Unit + (rec t. Unit + t)
        { unifyF matches the + and makes two calls to unify }
    Unit =:= Unit   { trivial}
    (Unit + (rec s. Unit + Unit + s))        =:= (rec t. Unit + t)
        { unfold the RHS }
    (Unit + (rec s. Unit + Unit + s))        =:= (Unit + (rec t. Unit + t))
        { unifyF on + }
    (rec s. Unit + Unit + s)                 =:= (rec t. Unit + t)
        { back to the starting pair, return success }
  

unifyVar :: forall (sig :: (Type -> Type) -> Type -> Type) m. (Has (Throw UnificationError) sig m, Has (Reader TDCtx) sig m, Has (State (Subst IntVar UType)) sig m, Has (State (Set (UType, UType))) sig m) => IntVar -> UType -> m UType Source #

Unify a unification variable which is not bound by the current substitution with another term. If the other term is also a variable, we must look it up as well to see if it is bound.

unifyF :: forall (sig :: (Type -> Type) -> Type -> Type) m. (Has (Throw UnificationError) sig m, Has (Reader TDCtx) sig m, Has (State (Subst IntVar UType)) sig m, Has (State (Set (UType, UType))) sig m) => TypeF UType -> TypeF UType -> m (TypeF UType) Source #

Perform unification on two non-variable terms: check that they have the same top-level constructor and recurse on their contents.