Newer
Older
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
78
79
80
81
82
83
84
85
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RankNTypes #-}
-- |
--
-- Module: Control.RTree
module Control.RTree where
import Control.Monad (MonadPlus (..), ap, liftM2)
import Data.Functor
-- | The reduction tree, parameterized by a genrative functor 'f'.
data ReduceT f i
= Done i
| f (ReduceT f i) :<| ReduceT f i
instance (Functor f) => Functor (ReduceT f) where
fmap f = \case
Done i -> Done (f i)
mi :<| ri -> fmap (fmap f) mi :<| fmap f ri
instance (Functor f) => Applicative (ReduceT f) where
pure = Done
(<*>) = ap
instance (Functor f) => Monad (ReduceT f) where
ma >>= fa = case ma of
Done i -> fa i
mi :<| ri -> ((>>= fa) <$> mi) :<| (ri >>= fa)
-- | Change the underlying monad using a natural transformation.
liftR :: (Functor f) => (forall a. f a -> g a) -> ReduceT f i -> ReduceT g i
liftR nat = \case
Done i -> Done i
lhs :<| rhs -> nat (liftR nat <$> lhs) :<| liftR nat rhs
-- | Extract the input from the reducer.
extract :: ReduceT f i -> i
extract = \case
Done i -> i
_ :<| rhs -> extract rhs
-- | Reduce an input using a monad.
reduce :: (MonadPlus m) => (i -> m ()) -> ReduceT m i -> m i
reduce fn rt = case rt of
Done i -> fn i $> i
lhs :<| rhs -> do
(lhs >>= reduce fn) `mplus` reduce fn rhs
infixr 3 <|
-- Combinators
(<|) :: (Applicative f) => ReduceT f i -> ReduceT f i -> ReduceT f i
f <| b = pure f :<| b
-- | Split the world on a fact. False it does not happen, and True it does happen.
given :: (Applicative f) => ReduceT f Bool
given = pure False <| pure True
-- | A reducer is something that takes an inputs and returns a reduction tree.
type Reducer m i = i -> ReduceT m i
-- | A reducer should extract itself
-- @
-- extract . red = id
-- @
lawReduceId :: (Eq i) => Reducer m i -> i -> Bool
lawReduceId red i = extract (red i) == i
rList :: (Applicative m) => Reducer m [a]
rList = \case
[] -> Done []
a : as -> rList as <| (a :) <$> rList as
rBinaryList :: (Applicative m) => Reducer m [a]
rBinaryList = \case
[] -> Done []
as -> Done [] <| go as
where
go = \case
[] -> error "unexpected"
[a] -> Done [a]
as -> go l <| liftM2 (<>) (go f) (Done [] <| go l)
where
(f, l) = splitAt (length as `div` 2) as