| Copyright | (c) 2007-2014 Dan Doel (c) 2011-2013 Edward Kmett (c) 2014 Roman Cheplyaka (c) 2020-2021 Andrew Lelechenko (c) 2020-2021 Kevin Quick | 
|---|---|
| License | BSD3 | 
| Maintainer | Andrew Lelechenko <andrew.lelechenko@gmail.com> | 
| Safe Haskell | Trustworthy | 
| Language | Haskell2010 | 
Control.Monad.Logic
Description
Adapted from the paper
 Backtracking, Interleaving, and Terminating Monad Transformers
 by Oleg Kiselyov, Chung-chieh Shan, Daniel P. Friedman, Amr Sabry.
 Note that the paper uses MonadPlus vocabulary
 (mzero and mplus),
 while examples below prefer empty and <|>
 from Alternative.
Synopsis
- module Control.Monad.Logic.Class
- type Logic = LogicT Identity
- logic :: (forall r. (a -> r -> r) -> r -> r) -> Logic a
- runLogic :: Logic a -> (a -> r -> r) -> r -> r
- observe :: Logic a -> a
- observeMany :: Int -> Logic a -> [a]
- observeAll :: Logic a -> [a]
- newtype LogicT (m :: Type -> Type) a = LogicT {- unLogicT :: forall r. (a -> m r -> m r) -> m r -> m r
 
- runLogicT :: LogicT m a -> (a -> m r -> m r) -> m r -> m r
- observeT :: MonadFail m => LogicT m a -> m a
- observeManyT :: Monad m => Int -> LogicT m a -> m [a]
- observeAllT :: Applicative m => LogicT m a -> m [a]
- fromLogicT :: forall t (m :: Type -> Type) a. (Alternative (t m), MonadTrans t, Monad m, Monad (t m)) => LogicT m a -> t m a
- fromLogicTWith :: (Applicative m, Monad n, Alternative n) => (forall x. m x -> n x) -> LogicT m a -> n a
- hoistLogicT :: (Applicative m, Monad n) => (forall x. m x -> n x) -> LogicT m a -> LogicT n a
- embedLogicT :: forall m (n :: Type -> Type) b. Applicative m => (forall a. m a -> LogicT n a) -> LogicT m b -> LogicT n b
Documentation
module Control.Monad.Logic.Class
The Logic monad
type Logic = LogicT Identity #
The basic Logic monad, for performing backtracking computations
 returning values (e.g. Logic a will return values of type a).
It's important to remember that Logic on its own is just
 a lawful list monad, behaving exactly as instance Monad [].
 One should explicitly use methods of MonadLogic such as (>>-) and interleave
 to get fair conjunction / disjunction. Note that usual
 lists have an instance of MonadLogic, so maybe you don't need Logic at all.
Technical perspective.
 Logic is a
 Boehm-Berarducci encoding
 of lists. Speaking plainly, its type is identical (up to Identity wrappers)
 to foldr applied to a given list. And this list itself can be reconstructed
 by supplying (:) and [].
import Data.Functor.Identity fromList :: [a] -> Logic a fromList xs = LogicT $ \cons nil -> foldr cons nil xs toList :: Logic a -> [a] toList (LogicT fld) = runIdentity $ fld (\x (Identity xs) -> Identity (x : xs)) (Identity [])
Here is a systematic derivation of the isomorphism. We start with observing
 that [a] is isomorphic to a fix point of a non-recursive
 base algebra Fix (ListF a):
newtype Fix f = Fix (f (Fix f)) data ListF a r = ConsF a r | NilF deriving (Functor) cata :: Functor f => (f r -> r) -> Fix f -> r cata f = go where go (Fix x) = f (fmap go x) from :: [a] -> Fix (ListF a) from = foldr (\a acc -> Fix (ConsF a acc)) (Fix NilF) to :: Fix (ListF a) -> [a] to = cata (\case ConsF a r -> a : r; NilF -> [])
Further, Fix (ListF a) is isomorphic to Boehm-Berarducci encoding ListC a:
newtype ListC a = ListC (forall r. (ListF a r -> r) -> r) from :: Fix (ListF a) -> ListC a from xs = ListC (\f -> cata f xs) to :: ListC a -> Fix (ListF a) to (ListC f) = f Fix
Finally, ListF a r → r is isomorphic to a pair (a → r → r, r),
 so ListC is isomorphic to the Logic type modulo Identity wrappers:
newtype Logic a = Logic (forall r. (a -> r -> r) -> r -> r)
And wrapping every occurence of r into m gives us LogicT:
newtype LogicT m a = Logic (forall r. (a -> m r -> m r) -> m r -> m r)
Since: 0.5.0
logic :: (forall r. (a -> r -> r) -> r -> r) -> Logic a #
A smart constructor for Logic computations.
Since: 0.5.0
runLogic :: Logic a -> (a -> r -> r) -> r -> r #
Runs a Logic computation with the specified initial success and
 failure continuations.
>>>runLogic empty (+) 00
>>>runLogic (pure 5 <|> pure 3 <|> empty) (+) 08
When invoked with (:) and [] as arguments, reveals
 a half of the isomorphism between Logic and lists.
 See description of observeAll for the other half.
Since: 0.2
observeMany :: Int -> Logic a -> [a] #
Extracts up to a given number of results from a Logic computation.
>>>let nats = pure 0 <|> fmap (+ 1) nats>>>observeMany 5 nats[0,1,2,3,4]
Since Logic is isomorphic to a list, observeMany is analogous to take.
Since: 0.2
observeAll :: Logic a -> [a] #
Extracts all results from a Logic computation.
>>>observeAll (pure 5 <|> empty <|> empty <|> pure 3 <|> empty)[5,3]
observeAll reveals a half of the isomorphism between Logic
 and lists. See description of runLogic for the other half.
Since: 0.2
The LogicT monad transformer
newtype LogicT (m :: Type -> Type) a #
A monad transformer for performing backtracking computations
 layered over another monad m.
When m is Identity, LogicT m becomes isomorphic to a list
 (see Logic). Thus LogicT m for non-trivial m can be imagined
 as a list, pattern matching on which causes monadic effects.
It's important to remember that LogicT on its own is just
 a lawful list monad transformer, adding a nondeterministic effect,
 and its Monad instance behaves just as instance Monad []:
>>>:set -XOverloadedLists>>>observeMany 9 $ do {x <- [100,200] :: Logic Int; fmap (+x) [1..]}[101,102,103,104,105,106,107,108,109]>>>observeMany 9 $ do {[100,200] >>= \x -> fmap (+x) [1..] :: Logic Int}[101,102,103,104,105,106,107,108,109]
One should explicitly use methods of MonadLogic such as (>>-) and interleave
 to get fair conjunction / disjunction:
>>>observeMany 9 $ do {[100,200] >>- \x -> fmap (+x) [1..] :: Logic Int}[101,201,102,202,103,203,104,204,105]
Since: 0.2
Instances
| Foldable Logic # | Since: 0.5.0 | 
| Defined in Control.Monad.Logic Methods fold :: Monoid m => Logic m -> m # foldMap :: Monoid m => (a -> m) -> Logic a -> m # foldMap' :: Monoid m => (a -> m) -> Logic a -> m # foldr :: (a -> b -> b) -> b -> Logic a -> b # foldr' :: (a -> b -> b) -> b -> Logic a -> b # foldl :: (b -> a -> b) -> b -> Logic a -> b # foldl' :: (b -> a -> b) -> b -> Logic a -> b # foldr1 :: (a -> a -> a) -> Logic a -> a # foldl1 :: (a -> a -> a) -> Logic a -> a # elem :: Eq a => a -> Logic a -> Bool # maximum :: Ord a => Logic a -> a # minimum :: Ord a => Logic a -> a # | |
| MonadLogic Logic # | Since: 0.8.2.0 | 
| MonadTrans LogicT # | |
| Defined in Control.Monad.Logic | |
| MonadError e m => MonadError e (LogicT m) # | Since: 0.4 | 
| Defined in Control.Monad.Logic | |
| MonadReader r m => MonadReader r (LogicT m) # | |
| MonadState s m => MonadState s (LogicT m) # | |
| MonadIO m => MonadIO (LogicT m) # | |
| Defined in Control.Monad.Logic | |
| MonadZip m => MonadZip (LogicT m) # | Since: 0.8.0.0 | 
| MonadCatch m => MonadCatch (LogicT m) # | Since: 0.8.2.0 | 
| Defined in Control.Monad.Logic | |
| MonadThrow m => MonadThrow (LogicT m) # | Since: 0.8.2.0 | 
| Defined in Control.Monad.Logic Methods throwM :: (HasCallStack, Exception e) => e -> LogicT m a # | |
| Alternative (LogicT f) # | |
| Applicative (LogicT f) # | |
| Functor (LogicT f) # | |
| Monad (LogicT m) # | |
| MonadPlus (LogicT m) # | |
| MonadFail (LogicT m) # | Since: 0.6.0.3 | 
| Defined in Control.Monad.Logic | |
| (Applicative m, Foldable m) => Foldable (LogicT m) # | Since: 0.5.0 | 
| Defined in Control.Monad.Logic Methods fold :: Monoid m0 => LogicT m m0 -> m0 # foldMap :: Monoid m0 => (a -> m0) -> LogicT m a -> m0 # foldMap' :: Monoid m0 => (a -> m0) -> LogicT m a -> m0 # foldr :: (a -> b -> b) -> b -> LogicT m a -> b # foldr' :: (a -> b -> b) -> b -> LogicT m a -> b # foldl :: (b -> a -> b) -> b -> LogicT m a -> b # foldl' :: (b -> a -> b) -> b -> LogicT m a -> b # foldr1 :: (a -> a -> a) -> LogicT m a -> a # foldl1 :: (a -> a -> a) -> LogicT m a -> a # elem :: Eq a => a -> LogicT m a -> Bool # maximum :: Ord a => LogicT m a -> a # minimum :: Ord a => LogicT m a -> a # | |
| Traversable (LogicT Identity) # | Since: 0.5.0 | 
| Defined in Control.Monad.Logic Methods traverse :: Applicative f => (a -> f b) -> LogicT Identity a -> f (LogicT Identity b) # sequenceA :: Applicative f => LogicT Identity (f a) -> f (LogicT Identity a) # mapM :: Monad m => (a -> m b) -> LogicT Identity a -> m (LogicT Identity b) # sequence :: Monad m => LogicT Identity (m a) -> m (LogicT Identity a) # | |
| (Monad m, Traversable m) => Traversable (LogicT m) # | Since: 0.8.0.0 | 
| Defined in Control.Monad.Logic | |
| IsList (Logic a) # | Since: 0.8.2.0 | 
| Read a => Read (Logic a) # | Since: 0.8.2.0 | 
| Show a => Show (Logic a) # | Since: 0.8.2.0 | 
| Eq a => Eq (Logic a) # | Since: 0.8.2.0 | 
| Ord a => Ord (Logic a) # | Since: 0.8.2.0 | 
| Monad m => MonadLogic (LogicT m) # | |
| Defined in Control.Monad.Logic Methods msplit :: LogicT m a -> LogicT m (Maybe (a, LogicT m a)) # interleave :: LogicT m a -> LogicT m a -> LogicT m a # (>>-) :: LogicT m a -> (a -> LogicT m b) -> LogicT m b # once :: LogicT m a -> LogicT m a # lnot :: LogicT m a -> LogicT m () # ifte :: LogicT m a -> (a -> LogicT m b) -> LogicT m b -> LogicT m b # | |
| Monoid (LogicT m a) # | Since: 0.7.0.3 | 
| Semigroup (LogicT m a) # | Since: 0.7.0.3 | 
| type Item (Logic a) # | |
| Defined in Control.Monad.Logic | |
runLogicT :: LogicT m a -> (a -> m r -> m r) -> m r -> m r #
Runs a LogicT computation with the specified initial success and
 failure continuations.
The second argument ("success continuation") takes one result of
 the LogicT computation and the monad to run for any subsequent
 matches.
The third argument ("failure continuation") is called when the
 LogicT cannot produce any more results.
For example:
>>>yieldWords = foldr ((<|>) . pure) empty>>>showEach wrd nxt = putStrLn wrd >> nxt>>>runLogicT (yieldWords ["foo", "bar"]) showEach (putStrLn "none!")foo bar none!>>>runLogicT (yieldWords []) showEach (putStrLn "none!")none!>>>showFirst wrd _ = putStrLn wrd>>>runLogicT (yieldWords ["foo", "bar"]) showFirst (putStrLn "none!")foo
Since: 0.2
observeT :: MonadFail m => LogicT m a -> m a #
Extracts the first result from a LogicT computation,
 failing if there are no results at all.
Since: 0.2
observeManyT :: Monad m => Int -> LogicT m a -> m [a] #
Extracts up to a given number of results from a LogicT computation.
Since: 0.2
observeAllT :: Applicative m => LogicT m a -> m [a] #
Extracts all results from a LogicT computation, unless blocked by the
 underlying monad.
For example, given
>>>let nats = pure 0 <|> fmap (+ 1) nats
some monads (like Identity, Reader,
 Writer, and State)
 will be productive:
>>>take 5 $ runIdentity (observeAllT nats)[0,1,2,3,4]
but others (like ExceptT,
 and ContT) will not:
>>>take 20 <$> runExcept (observeAllT nats)
In general, if the underlying monad manages control flow then
 observeAllT may be unproductive under infinite branching,
 and observeManyT should be used instead.
Since: 0.2
fromLogicT :: forall t (m :: Type -> Type) a. (Alternative (t m), MonadTrans t, Monad m, Monad (t m)) => LogicT m a -> t m a #
Convert from LogicT to an arbitrary logic-like monad transformer,
 such as list-t
 or logict-sequence
For example, to show a representation of the structure of a LogicT
 computation, l, over a data-like Monad (such as [],
 Data.Sequence.Seq, etc.), you could write
import ListT (ListT)
show $ fromLogicT @ListT l
Since: 0.8.0.0
fromLogicTWith :: (Applicative m, Monad n, Alternative n) => (forall x. m x -> n x) -> LogicT m a -> n a #
Convert from LogicT m[].
Examples:
fromLogicT= fromLogicTWith dhoistLogicTf = fromLogicTWith (lift. f)embedLogicTf =fromLogicTWithf
The first argument should be a monad morphism. to produce sensible results.
Since: 0.8.0.0
hoistLogicT :: (Applicative m, Monad n) => (forall x. m x -> n x) -> LogicT m a -> LogicT n a #
Convert a LogicT computation from one underlying monad to another.
 For example,
hoistLogicT lift :: LogicT m a -> LogicT (StateT m) a
The first argument should be a monad morphism. to produce sensible results.
Since: 0.8.0.0
embedLogicT :: forall m (n :: Type -> Type) b. Applicative m => (forall a. m a -> LogicT n a) -> LogicT m b -> LogicT n b #
Convert a LogicT computation from one underlying monad to another.
The first argument should be a monad morphism. to produce sensible results.
Since: 0.8.0.0