Skip to content

Commit c17c481

Browse files
natefaubionpaf31
authored andcommitted
Lazy Cofree constructor (#92)
* Lazy Cofree constructor * Adds a `Lazy` instance. * Adds `buildCofree` which unfolds a label and subtree together. * Lazy hoistCofree * Rename liftC to deferCofree. Add note about buildCofree
1 parent 542a9da commit c17c481

File tree

2 files changed

+36
-18
lines changed

2 files changed

+36
-18
lines changed

bower.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
"purescript-catenable-lists": "^4.0.0",
2828
"purescript-exists": "^3.0.0",
2929
"purescript-transformers": "^3.0.0",
30-
"purescript-unsafe-coerce": "^3.0.0"
30+
"purescript-unsafe-coerce": "^3.0.0",
31+
"purescript-control": "^3.0.0"
3132
},
3233
"devDependencies": {
3334
"purescript-console": "^3.0.0",

src/Control/Comonad/Cofree.purs

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
module Control.Comonad.Cofree
44
( Cofree
5+
, deferCofree
56
, mkCofree, (:<)
67
, head
78
, tail
89
, hoistCofree
910
, unfoldCofree
11+
, buildCofree
1012
, explore
1113
, exploreM
1214
) where
@@ -15,6 +17,7 @@ import Prelude
1517
import Control.Alternative (class Alternative, (<|>), empty)
1618
import Control.Comonad (class Comonad, extract)
1719
import Control.Extend (class Extend)
20+
import Control.Lazy as Z
1821
import Control.Monad.Free (Free, runFreeM)
1922
import Control.Monad.Rec.Class (class MonadRec)
2023
import Control.Monad.State (State, StateT(..), runState, runStateT, state)
@@ -23,7 +26,7 @@ import Data.Foldable (class Foldable, foldr, foldl, foldMap)
2326
import Data.Lazy (Lazy, force, defer)
2427
import Data.Ord (class Ord1, compare1)
2528
import Data.Traversable (class Traversable, traverse)
26-
import Data.Tuple (Tuple(..))
29+
import Data.Tuple (Tuple(..), fst, snd)
2730

2831
-- | The `Cofree` `Comonad` for a functor.
2932
-- |
@@ -32,41 +35,51 @@ import Data.Tuple (Tuple(..))
3235
-- |
3336
-- | The `Comonad` instance supports _redecoration_, recomputing
3437
-- | labels from the local context.
35-
data Cofree f a = Cofree a (Lazy (f (Cofree f a)))
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
3644

3745
-- | Create a value of type `Cofree f a` from a label and a
3846
-- | functor-full of "subtrees".
3947
mkCofree :: forall f a. a -> f (Cofree f a) -> Cofree f a
40-
mkCofree a t = Cofree a (defer \_ -> t)
48+
mkCofree a t = Cofree (defer \_ -> Tuple a t)
4149

4250
infixr 5 mkCofree as :<
4351

4452
-- | Returns the label for a tree.
4553
head :: forall f a. Cofree f a -> a
46-
head (Cofree h _) = h
54+
head (Cofree c) = fst (force c)
4755

4856
-- | Returns the "subtrees" of a tree.
4957
tail :: forall f a. Cofree f a -> f (Cofree f a)
50-
tail (Cofree _ t) = force t
51-
52-
_tail :: forall f a. Cofree f a -> Lazy (f (Cofree f a))
53-
_tail (Cofree _ t) = t
54-
55-
_lift :: forall f a b. Functor f => (a -> b) -> Lazy (f a) -> Lazy (f b)
56-
_lift = map <<< map
58+
tail (Cofree c) = snd (force c)
5759

5860
hoistCofree :: forall f g. Functor f => (f ~> g) -> Cofree f ~> Cofree g
59-
hoistCofree nat cf = head cf :< nat (hoistCofree nat <$> tail cf)
61+
hoistCofree nat (Cofree c) = Cofree (map (nat <<< map (hoistCofree nat)) <$> c)
6062

63+
-- | This signature is deprecated and will be replaced by `buildCofree` in a
64+
-- | future release.
6165
unfoldCofree
6266
:: forall f s a
6367
. Functor f
6468
=> (s -> a)
6569
-> (s -> f s)
6670
-> s
6771
-> Cofree f a
68-
unfoldCofree e n s =
69-
Cofree (e s) (defer \_ -> unfoldCofree e n <$> n s)
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)
7083

7184
-- | Explore a value in the cofree comonad by using an expression in a
7285
-- | corresponding free monad.
@@ -122,8 +135,9 @@ instance ord1Cofree :: Ord1 f => Ord1 (Cofree f) where
122135
compare1 = compare
123136

124137
instance functorCofree :: Functor f => Functor (Cofree f) where
125-
map f = loop where
126-
loop fa = Cofree (f (head fa)) (_lift loop (_tail fa))
138+
map f = loop
139+
where
140+
loop (Cofree fa) = Cofree ((\(Tuple a b) -> Tuple (f a) (loop <$> b)) <$> fa)
127141

128142
instance foldableCofree :: Foldable f => Foldable (Cofree f) where
129143
foldr f = flip go
@@ -147,7 +161,7 @@ instance traversableCofree :: Traversable f => Traversable (Cofree f) where
147161
instance extendCofree :: Functor f => Extend (Cofree f) where
148162
extend f = loop
149163
where
150-
loop fa = Cofree (f fa) (_lift loop (_tail fa))
164+
loop (Cofree fa) = Cofree ((\(Tuple a b) -> Tuple (f (Cofree fa)) (loop <$> b)) <$> fa)
151165

152166
instance comonadCofree :: Functor f => Comonad (Cofree f) where
153167
extract = head
@@ -166,3 +180,6 @@ instance bindCofree :: Alternative f => Bind (Cofree f) where
166180
in mkCofree (head fh) ((tail fh) <|> (loop <$> tail fa'))
167181

168182
instance monadCofree :: Alternative f => Monad (Cofree f)
183+
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)