Skip to content

Commit 1a92ae8

Browse files
re-add compat module for cofree
1 parent bed6eee commit 1a92ae8

File tree

1 file changed

+176
-20
lines changed

1 file changed

+176
-20
lines changed
Lines changed: 176 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,185 @@
1-
module Control.Comonad.Cofree.Class.Compat
2-
( class ComonadCofree
3-
, unwrapCofree
1+
-- | The _cofree comonad_ for a `Functor`.
2+
3+
module Control.Comonad.Cofree.Compat
4+
( Cofree
5+
, deferCofree
6+
, mkCofree, (:<)
7+
, head
8+
, tail
9+
, hoistCofree
10+
, unfoldCofree
11+
, buildCofree
12+
, explore
13+
, exploreM
414
) where
515

616
import Prelude
17+
import Control.Alternative (class Alternative, (<|>), empty)
18+
import Control.Comonad (class Comonad, extract)
19+
import Control.Extend (class Extend)
20+
import Control.Lazy as Z
21+
import Control.Monad.Free.Compat (Free, runFreeM)
22+
import Control.Monad.Rec.Class (class MonadRec)
23+
import Control.Monad.State (State, StateT(..), runState, runStateT, state)
24+
import Data.Eq (class Eq1, eq1)
25+
import Data.Foldable (class Foldable, foldr, foldl, foldMap)
26+
import Data.Lazy (Lazy, force, defer)
27+
import Data.Ord (class Ord1, compare1)
28+
import Data.Traversable (class Traversable, traverse)
29+
import Data.Tuple (Tuple(..), fst, snd)
30+
31+
-- | The `Cofree` `Comonad` for a functor.
32+
-- |
33+
-- | A value of type `Cofree f a` consists of an `f`-branching
34+
-- | tree, annotated with labels of type `a`.
35+
-- |
36+
-- | The `Comonad` instance supports _redecoration_, recomputing
37+
-- | labels from the local context.
38+
newtype Cofree f a = Cofree (Lazy (Tuple a (f (Cofree f a))))
39+
40+
-- | Lazily creates a value of type `Cofree f a` from a label and a
41+
-- | functor-full of "subtrees".
42+
deferCofree :: forall f a. (Unit -> Tuple a (f (Cofree f a))) -> Cofree f a
43+
deferCofree = Cofree <<< defer
44+
45+
-- | Create a value of type `Cofree f a` from a label and a
46+
-- | functor-full of "subtrees".
47+
mkCofree :: forall f a. a -> f (Cofree f a) -> Cofree f a
48+
mkCofree a t = Cofree (defer \_ -> Tuple a t)
49+
50+
infixr 5 mkCofree as :<
51+
52+
-- | Returns the label for a tree.
53+
head :: forall f a. Cofree f a -> a
54+
head (Cofree c) = fst (force c)
55+
56+
-- | Returns the "subtrees" of a tree.
57+
tail :: forall f a. Cofree f a -> f (Cofree f a)
58+
tail (Cofree c) = snd (force c)
59+
60+
hoistCofree :: forall f g. Functor f => (f ~> g) -> Cofree f ~> Cofree g
61+
hoistCofree nat (Cofree c) = Cofree (map (nat <<< map (hoistCofree nat)) <$> c)
62+
63+
-- | This signature is deprecated and will be replaced by `buildCofree` in a
64+
-- | future release.
65+
unfoldCofree
66+
:: forall f s a
67+
. Functor f
68+
=> (s -> a)
69+
-> (s -> f s)
70+
-> s
71+
-> Cofree f a
72+
unfoldCofree e n = buildCofree (\s -> Tuple (e s) (n s))
73+
74+
-- | Recursively unfolds a `Cofree` structure given a seed.
75+
buildCofree
76+
:: forall f s a
77+
. Functor f
78+
=> (s -> Tuple a (f s))
79+
-> s
80+
-> Cofree f a
81+
buildCofree k s =
82+
Cofree (defer \_ -> map (buildCofree k) <$> k s)
83+
84+
-- | Explore a value in the cofree comonad by using an expression in a
85+
-- | corresponding free monad.
86+
-- |
87+
-- | The free monad should be built from a functor which pairs with the
88+
-- | functor underlying the cofree comonad.
89+
explore
90+
:: forall f g a b
91+
. Functor f
92+
=> Functor g
93+
=> (forall x y. f (x -> y) -> g x -> y)
94+
-> Free f (a -> b)
95+
-> Cofree g a
96+
-> b
97+
explore pair m w =
98+
case runState (runFreeM step m) w of
99+
Tuple f cof -> f (extract cof)
100+
where
101+
step :: f (Free f (a -> b)) -> State (Cofree g a) (Free f (a -> b))
102+
step ff = state \cof -> pair (map Tuple ff) (tail cof)
103+
104+
exploreM
105+
:: forall f g a b m
106+
. Functor f
107+
=> Functor g
108+
=> MonadRec m
109+
=> (forall x y. f (x -> y) -> g x -> m y)
110+
-> Free f (a -> b)
111+
-> Cofree g a
112+
-> m b
113+
exploreM pair m w =
114+
eval <$> runStateT (runFreeM step m) w
115+
where
116+
step :: f (Free f (a -> b)) -> StateT (Cofree g a) m (Free f (a -> b))
117+
step ff = StateT \cof -> pair (map Tuple ff) (tail cof)
118+
119+
eval :: forall x y. Tuple (x -> y) (Cofree g x) -> y
120+
eval (Tuple f cof) = f (extract cof)
121+
122+
instance eqCofree :: (Eq1 f, Eq a) => Eq (Cofree f a) where
123+
eq x y = head x == head y && tail x `eq1` tail y
124+
125+
instance eq1Cofree :: Eq1 f => Eq1 (Cofree f) where
126+
eq1 = eq
127+
128+
instance ordCofree :: (Ord1 f, Ord a) => Ord (Cofree f a) where
129+
compare x y =
130+
case compare (head x) (head y) of
131+
EQ -> compare1 (tail x) (tail y)
132+
r -> r
133+
134+
instance ord1Cofree :: Ord1 f => Ord1 (Cofree f) where
135+
compare1 = compare
136+
137+
instance functorCofree :: Functor f => Functor (Cofree f) where
138+
map f = loop
139+
where
140+
loop (Cofree fa) = Cofree ((\(Tuple a b) -> Tuple (f a) (loop <$> b)) <$> fa)
141+
142+
instance foldableCofree :: Foldable f => Foldable (Cofree f) where
143+
foldr f = flip go
144+
where
145+
go fa b = f (head fa) (foldr go b (tail fa))
146+
147+
foldl f = go
148+
where
149+
go b fa = foldl go (f b (head fa)) (tail fa)
150+
151+
foldMap f = go
152+
where
153+
go fa = f (head fa) <> (foldMap go (tail fa))
154+
155+
instance traversableCofree :: Traversable f => Traversable (Cofree f) where
156+
sequence = traverse identity
157+
traverse f = loop
158+
where
159+
loop ta = mkCofree <$> f (head ta) <*> (traverse loop (tail ta))
160+
161+
instance extendCofree :: Functor f => Extend (Cofree f) where
162+
extend f = loop
163+
where
164+
loop (Cofree fa) = Cofree ((\(Tuple a b) -> Tuple (f (Cofree fa)) (loop <$> b)) <$> fa)
7165

8-
import Control.Comonad (class Comonad)
9-
import Control.Comonad.Cofree.Compat (Cofree, tail)
10-
import Control.Comonad.Env.Trans (EnvT(..))
11-
import Control.Comonad.Store.Trans (StoreT(..))
12-
import Control.Comonad.Traced.Trans (TracedT(..))
13-
import Data.Tuple (Tuple(..))
166+
instance comonadCofree :: Functor f => Comonad (Cofree f) where
167+
extract = head
14168

15-
-- | Based on <http://hackage.haskell.org/package/free/docs/Control-Comonad-Cofree-Class.html>
16-
class (Functor f, Comonad w) <= ComonadCofree f w | w -> f where
17-
unwrapCofree :: forall a. w a -> f (w a)
169+
instance applyCofree :: Alternative f => Apply (Cofree f) where
170+
apply = ap
18171

19-
instance comonadCofreeCofree :: Functor f => ComonadCofree f (Cofree f) where
20-
unwrapCofree = tail
172+
instance applicativeCofree :: Alternative f => Applicative (Cofree f) where
173+
pure a = mkCofree a empty
21174

22-
instance comonadCofreeEnvT :: (Functor f, ComonadCofree f w) => ComonadCofree f (EnvT e w) where
23-
unwrapCofree (EnvT (Tuple e wa)) = map (\x -> EnvT (Tuple e x)) (unwrapCofree wa)
175+
instance bindCofree :: Alternative f => Bind (Cofree f) where
176+
bind fa f = loop fa
177+
where
178+
loop fa' =
179+
let fh = f (head fa')
180+
in mkCofree (head fh) ((tail fh) <|> (loop <$> tail fa'))
24181

25-
instance comonadCofreeStoreT :: (Functor f, ComonadCofree f w) => ComonadCofree f (StoreT s w) where
26-
unwrapCofree (StoreT (Tuple wsa s)) = map (\x -> StoreT (Tuple x s)) (unwrapCofree wsa)
182+
instance monadCofree :: Alternative f => Monad (Cofree f)
27183

28-
instance comonadCofreeTracedT :: (Functor f, ComonadCofree f w, Monoid m) => ComonadCofree f (TracedT m w) where
29-
unwrapCofree (TracedT wma) = map TracedT (unwrapCofree wma)
184+
instance lazyCofree :: Z.Lazy (Cofree f a) where
185+
defer k = Cofree (defer \_ -> let (Cofree t) = k unit in force t)

0 commit comments

Comments
 (0)