summaryrefslogtreecommitdiff
path: root/compiler/utils/ListT.hs
blob: c16701419d886c25c67ff94e5330325ffe207170 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}

-------------------------------------------------------------------------
-- |
-- Module      : Control.Monad.Logic
-- Copyright   : (c) Dan Doel
-- License     : BSD3
--
-- Maintainer  : dan.doel@gmail.com
-- Stability   : experimental
-- Portability : non-portable (multi-parameter type classes)
--
-- A backtracking, logic programming monad.
--
--    Adapted from the paper
--    /Backtracking, Interleaving, and Terminating
--        Monad Transformers/, by
--    Oleg Kiselyov, Chung-chieh Shan, Daniel P. Friedman, Amr Sabry
--    (<http://www.cs.rutgers.edu/~ccshan/logicprog/ListT-icfp2005.pdf>).
-------------------------------------------------------------------------

module ListT (
    ListT(..),
    runListT,
    select,
    fold
  ) where

import GhcPrelude

import Control.Applicative

import Control.Monad
import Control.Monad.Fail as MonadFail

-------------------------------------------------------------------------
-- | A monad transformer for performing backtracking computations
-- layered over another monad 'm'
newtype ListT m a =
    ListT { unListT :: forall r. (a -> m r -> m r) -> m r -> m r }

select :: Monad m => [a] -> ListT m a
select xs = foldr (<|>) mzero (map pure xs)

fold :: ListT m a -> (a -> m r -> m r) -> m r -> m r
fold = runListT

-------------------------------------------------------------------------
-- | Runs a ListT computation with the specified initial success and
-- failure continuations.
runListT :: ListT m a -> (a -> m r -> m r) -> m r -> m r
runListT = unListT

instance Functor (ListT f) where
    fmap f lt = ListT $ \sk fk -> unListT lt (sk . f) fk

instance Applicative (ListT f) where
    pure a = ListT $ \sk fk -> sk a fk
    f <*> a = ListT $ \sk fk -> unListT f (\g fk' -> unListT a (sk . g) fk') fk

instance Alternative (ListT f) where
    empty = ListT $ \_ fk -> fk
    f1 <|> f2 = ListT $ \sk fk -> unListT f1 sk (unListT f2 sk fk)

instance Monad (ListT m) where
    m >>= f = ListT $ \sk fk -> unListT m (\a fk' -> unListT (f a) sk fk') fk
    fail = MonadFail.fail

instance MonadFail (ListT m) where
    fail _ = ListT $ \_ fk -> fk

instance MonadPlus (ListT m) where
    mzero = ListT $ \_ fk -> fk
    m1 `mplus` m2 = ListT $ \sk fk -> unListT m1 sk (unListT m2 sk fk)