% Constraint Functional-Logic Programming
% Sebastian Fischer (sebf@informatik.uni-kiel.de)
This module provides an interface that can be used for constraint
functional-logic programming in Haskell.
>
>
> module Control.CFLP (
>
> CFLP, CS, UpdateT, ChoiceStore, Computation, eval, evalPartial, evalPrint,
>
> Strategy, depthFirst,
>
> module Data.LazyNondet
>
> ) where
>
> import Data.LazyNondet
>
> import Control.Monad.State
> import Control.Monad.Update
> import Control.Monad.Trans.Update
>
> import Control.Constraint.Choice
>
> class (MonadUpdate s m, Update s m m, ChoiceStore s) => CFLP s m
The type class `CFLP` is a shortcut for the type-class constraints on
constraint functional-logic computations that are parameterized over a
constraint store and a constraint monad. Hence, such computations can
be executed with different constraint stores and search strategies.
> instance CFLP ChoiceStoreIM (UpdateT ChoiceStoreIM [])
We declare instances for every combination of monad and constraint
store that we intend to use.
> type CS = ChoiceStoreIM
>
> noConstraints :: Context CS
> noConstraints = Context noChoices
>
> type Computation m a = Context CS -> ID -> Nondet CS (UpdateT CS m) a
Currently, the constraint store used to evaluate constraint
functional-logic programs is simply a `ChoiceStore`. It will be a
combination of different constraint stores, when more constraint
solvers have been implemented.
> type Strategy m = forall a . m a -> [a]
A `Strategy` specifies how to enumerate non-deterministic results in a
list.
> depthFirst :: Strategy []
> depthFirst = id
The strategy of the list monad is depth-first search.
> evaluate :: (CFLP CS m, Update CS m m')
> => (Nondet CS m a -> Context CS -> m' b)
> -> Strategy m' -> (Context CS -> ID -> Nondet CS m a)
> -> IO [b]
> evaluate evalNondet enumerate op = do
> i <- initID
> return $ enumerate $ evalNondet (op noConstraints i) noConstraints
The `evaluate` function enumerates the non-deterministic solutions of a
constraint functional-logic computation according to a given strategy.
> eval, evalPartial :: (CFLP CS m, Update CS m m', Generic a)
> => Strategy m' -> (Context CS -> ID -> Nondet CS m a)
> -> IO [a]
> eval s = liftM (map primitive) . evaluate groundNormalForm s
> evalPartial s = liftM (map primitive) . evaluate partialNormalForm s
>
> evalPrint :: (CFLP CS m, Update CS m m', Generic a)
> => Strategy m' -> (Context CS -> ID -> Nondet CS m a)
> -> IO ()
> evalPrint s op = evaluate partialNormalForm s op >>= printSols
>
> printSols :: Show a => [a] -> IO ()
> printSols [] = putStrLn "No more solutions."
> printSols (x:xs) = do
> print x
> putStr "more? [Y(es)|n(o)|a(ll)]: "
> s <- getLine
> if s `elem` ["n","no"] then
> return ()
> else if s `elem` ["a","all"]
> then mapM_ print xs
> else printSols xs
We provide
* an `eval` operation to compute Haskell terms from
non-deterministic data,
* an operation `evalPartial` to compute partial Haskell terms where
logic variables are replaced with an error, and
* an `evalPrint` operation that interactively shows (partial)
solutions of a constraint functional-logic computation.