% Sharing Choices with Constraints
% Sebastian Fischer (sebf@informatik.uni-kiel.de)
We define a constraint store that stores choice constraints which
ensure that shared non-deterministic choices evaluate to the same
values when translating lazy functional logic programs.
Based on this constraint store, we provide a function `choice` that
can be used to generate choices that are constrained to evaluate to
the same value if they are shared.
>
>
> module Control.Monad.Constraint.Choice (
>
> Choice, ChoiceStore, noChoices, choice
>
> ) where
>
> import Control.Monad
> import Control.Monad.State
> import Control.Monad.Constraint
>
> import Unique
> import UniqSupply
> import UniqFM
We borrow unique identifiers from the package `ghc` which is hidden by
default.
> newtype Choice = Choice (Unique,Int)
> newtype ChoiceStore = ChoiceStore (UniqFM Int)
>
> noChoices :: ChoiceStore
> noChoices = ChoiceStore emptyUFM
>
> instance ConstraintStore Choice ChoiceStore
> where
> assert (Choice (u,x)) = do
> ChoiceStore cs <- get
> maybe (put (ChoiceStore (addToUFM_Directly cs u x)))
> (guard . (x==))
> (lookupUFM_Directly cs u)
Choices are labeled with a `Unique`, so we can store them in a
`UniqFM` making it an instance of `ConstraintStore`.
The `assert` operations fails to insert conflicting choices.
> choice :: MonadConstr Choice m => Unique -> [m a] -> m a
> choice u = foldr1 mplus . (mzero:) . zipWith constrain [(0::Int)..]
> where constrain n = (constr (Choice (u,n))>>)
The operation `choice` takes a unique label and a list of monadic
values that can be constrained with choice constraints. The result is
a single monadic action combining the alternatives with `mplus`. If it
occurs more than once in a bigger monadic action, the result is
constrained to take the same alternative everywhere when collecting
constraints.