diff --git a/benchmark/Benchmark/Free.purs b/benchmark/Benchmark/Free.purs new file mode 100644 index 0000000..20178d2 --- /dev/null +++ b/benchmark/Benchmark/Free.purs @@ -0,0 +1,3 @@ +module Benchmark.Free (module Control.Monad.Free) where + +import Control.Monad.Free diff --git a/benchmark/Benchmark/Main.purs b/benchmark/Benchmark/Main.purs index 207faec..dc8274a 100644 --- a/benchmark/Benchmark/Main.purs +++ b/benchmark/Benchmark/Main.purs @@ -2,7 +2,9 @@ module Benchmark.Main (main) where import Prelude +import Benchmark.Free as Free import Benchmark.Freef686f5f as Freef686f5f +import Benchmark.Trampoline as Trampoline import Benchmark.Trampoline0df59c5 as Trampoline0df59c5 import Benchmark.Trampolinef686f5f as Trampolinef686f5f import Benchotron.Core (Benchmark, benchFn, mkBenchmark) @@ -30,25 +32,32 @@ leftBindSmallBenchmark = , inputsPerSize: inputsPerSize , gen: \n -> vectorOf n (pure 0.0) , functions: - [ benchFn "Free v5.2.0" (Trampolinef686f5f.runTrampoline <<< binds) - , benchFn "Free v0.6.1" (Trampoline0df59c5.runTrampoline <<< bindsT) + [ benchFn "Free (master)" (Trampoline.runTrampoline <<< binds) + , benchFn "Free v5.2.0" (Trampolinef686f5f.runTrampoline <<< binds_5_2_0) + , benchFn "Free v0.6.1" (Trampoline0df59c5.runTrampoline <<< binds_0_6_1) ] } where inputsPerSize :: Int inputsPerSize = 100 - binds :: Array Number -> Trampolinef686f5f.Trampoline Number + binds :: Array Number -> Trampoline.Trampoline Number binds as = foldl (\b a -> b >>= const (gen a)) (gen 0.0) as - gen :: forall a. a -> Trampolinef686f5f.Trampoline a - gen = Freef686f5f.suspendF <<< Trampolinef686f5f.done + gen :: forall a. a -> Trampoline.Trampoline a + gen = Free.suspendF <<< Trampoline.done - bindsT :: Array Number -> Trampoline0df59c5.Trampoline Number - bindsT as = foldl (\b a -> b >>= const (genT a)) (genT 0.0) as + binds_5_2_0 :: Array Number -> Trampolinef686f5f.Trampoline Number + binds_5_2_0 as = foldl (\b a -> b >>= const (gen_5_2_0 a)) (gen_5_2_0 0.0) as - genT :: forall a. a -> Trampoline0df59c5.Trampoline a - genT = Trampoline0df59c5.suspend <<< Trampoline0df59c5.done + gen_5_2_0 :: forall a. a -> Trampolinef686f5f.Trampoline a + gen_5_2_0 = Freef686f5f.suspendF <<< Trampolinef686f5f.done + + binds_0_6_1 :: Array Number -> Trampoline0df59c5.Trampoline Number + binds_0_6_1 as = foldl (\b a -> b >>= const (gen_0_6_1 a)) (gen_0_6_1 0.0) as + + gen_0_6_1 :: forall a. a -> Trampoline0df59c5.Trampoline a + gen_0_6_1 = Trampoline0df59c5.suspend <<< Trampoline0df59c5.done rightBindSmallBenchmark :: Benchmark rightBindSmallBenchmark = @@ -60,25 +69,32 @@ rightBindSmallBenchmark = , inputsPerSize: inputsPerSize , gen: \n -> vectorOf n (pure 0.0) , functions: - [ benchFn "Free v5.2.0" (Trampolinef686f5f.runTrampoline <<< binds) - , benchFn "Free v0.6.1" (Trampoline0df59c5.runTrampoline <<< bindsT) + [ benchFn "Free (master)" (Trampoline.runTrampoline <<< binds) + , benchFn "Free v5.2.0" (Trampolinef686f5f.runTrampoline <<< binds_5_2_0) + , benchFn "Free v0.6.1" (Trampoline0df59c5.runTrampoline <<< binds_0_6_1) ] } where inputsPerSize :: Int inputsPerSize = 100 - binds :: Array Number -> Trampolinef686f5f.Trampoline Number + binds :: Array Number -> Trampoline.Trampoline Number binds as = foldl (\b a -> gen a >>= const b) (gen 0.0) as - gen :: forall a. a -> Trampolinef686f5f.Trampoline a - gen = Freef686f5f.suspendF <<< Trampolinef686f5f.done + gen :: forall a. a -> Trampoline.Trampoline a + gen = Free.suspendF <<< Trampoline.done + + binds_5_2_0 :: Array Number -> Trampolinef686f5f.Trampoline Number + binds_5_2_0 as = foldl (\b a -> gen_5_2_0 a >>= const b) (gen_5_2_0 0.0) as + + gen_5_2_0 :: forall a. a -> Trampolinef686f5f.Trampoline a + gen_5_2_0 = Freef686f5f.suspendF <<< Trampolinef686f5f.done - bindsT :: Array Number -> Trampoline0df59c5.Trampoline Number - bindsT as = foldl (\b a -> genT a >>= const b) (genT 0.0) as + binds_0_6_1 :: Array Number -> Trampoline0df59c5.Trampoline Number + binds_0_6_1 as = foldl (\b a -> gen_0_6_1 a >>= const b) (gen_0_6_1 0.0) as - genT :: forall a. a -> Trampoline0df59c5.Trampoline a - genT = Trampoline0df59c5.suspend <<< Trampoline0df59c5.done + gen_0_6_1 :: forall a. a -> Trampoline0df59c5.Trampoline a + gen_0_6_1 = Trampoline0df59c5.suspend <<< Trampoline0df59c5.done leftBindLargeBenchmark :: Benchmark leftBindLargeBenchmark = @@ -90,26 +106,33 @@ leftBindLargeBenchmark = , inputsPerSize: inputsPerSize , gen: \n -> vectorOf n (pure 0.0) , functions: - [ benchFn "Free v5.2.0" (Trampolinef686f5f.runTrampoline <<< binds) + [ benchFn "Free (master)" (Trampoline.runTrampoline <<< binds) + , benchFn "Free v5.2.0" (Trampolinef686f5f.runTrampoline <<< binds_5_2_0) -- Disabled due to stack overflow - -- , benchFn "Free v0.6.1" (Trampoline0df59c5.runTrampoline <<< bindsT) + -- , benchFn "Free v0.6.1" (Trampoline0df59c5.runTrampoline <<< binds_0_6_1) ] } where inputsPerSize :: Int inputsPerSize = 1 - binds :: Array Number -> Trampolinef686f5f.Trampoline Number + binds :: Array Number -> Trampoline.Trampoline Number binds as = foldl (\b a -> b >>= const (gen a)) (gen 0.0) as - gen :: forall a. a -> Trampolinef686f5f.Trampoline a - gen = Freef686f5f.suspendF <<< Trampolinef686f5f.done + gen :: forall a. a -> Trampoline.Trampoline a + gen = Free.suspendF <<< Trampoline.done - bindsT :: Array Number -> Trampoline0df59c5.Trampoline Number - bindsT as = foldl (\b a -> b >>= const (genT a)) (genT 0.0) as + binds_5_2_0 :: Array Number -> Trampolinef686f5f.Trampoline Number + binds_5_2_0 as = foldl (\b a -> b >>= const (gen_5_2_0 a)) (gen_5_2_0 0.0) as - genT :: forall a. a -> Trampoline0df59c5.Trampoline a - genT = Trampoline0df59c5.suspend <<< Trampoline0df59c5.done + gen_5_2_0 :: forall a. a -> Trampolinef686f5f.Trampoline a + gen_5_2_0 = Freef686f5f.suspendF <<< Trampolinef686f5f.done + + binds_0_6_1 :: Array Number -> Trampoline0df59c5.Trampoline Number + binds_0_6_1 as = foldl (\b a -> b >>= const (gen_0_6_1 a)) (gen_0_6_1 0.0) as + + gen_0_6_1 :: forall a. a -> Trampoline0df59c5.Trampoline a + gen_0_6_1 = Trampoline0df59c5.suspend <<< Trampoline0df59c5.done rightBindLargeBenchmark :: Benchmark rightBindLargeBenchmark = @@ -121,22 +144,29 @@ rightBindLargeBenchmark = , inputsPerSize: inputsPerSize , gen: \n -> vectorOf n (pure 0.0) , functions: - [ benchFn "Free v5.2.0" (Trampolinef686f5f.runTrampoline <<< binds) - , benchFn "Free v0.6.1" (Trampoline0df59c5.runTrampoline <<< bindsT) + [ benchFn "Free (master)" (Trampoline.runTrampoline <<< binds) + , benchFn "Free v5.2.0" (Trampolinef686f5f.runTrampoline <<< binds_5_2_0) + , benchFn "Free v0.6.1" (Trampoline0df59c5.runTrampoline <<< binds_0_6_1) ] } where inputsPerSize :: Int inputsPerSize = 1 - binds :: Array Number -> Trampolinef686f5f.Trampoline Number + binds :: Array Number -> Trampoline.Trampoline Number binds as = foldl (\b a -> gen a >>= const b) (gen 0.0) as - gen :: forall a. a -> Trampolinef686f5f.Trampoline a - gen = Freef686f5f.suspendF <<< Trampolinef686f5f.done + gen :: forall a. a -> Trampoline.Trampoline a + gen = Free.suspendF <<< Trampoline.done + + binds_5_2_0 :: Array Number -> Trampolinef686f5f.Trampoline Number + binds_5_2_0 as = foldl (\b a -> gen_5_2_0 a >>= const b) (gen_5_2_0 0.0) as + + gen_5_2_0 :: forall a. a -> Trampolinef686f5f.Trampoline a + gen_5_2_0 = Freef686f5f.suspendF <<< Trampolinef686f5f.done - bindsT :: Array Number -> Trampoline0df59c5.Trampoline Number - bindsT as = foldl (\b a -> genT a >>= const b) (genT 0.0) as + binds_0_6_1 :: Array Number -> Trampoline0df59c5.Trampoline Number + binds_0_6_1 as = foldl (\b a -> gen_0_6_1 a >>= const b) (gen_0_6_1 0.0) as - genT :: forall a. a -> Trampoline0df59c5.Trampoline a - genT = Trampoline0df59c5.suspend <<< Trampoline0df59c5.done + gen_0_6_1 :: forall a. a -> Trampoline0df59c5.Trampoline a + gen_0_6_1 = Trampoline0df59c5.suspend <<< Trampoline0df59c5.done diff --git a/benchmark/Benchmark/Trampoline.purs b/benchmark/Benchmark/Trampoline.purs new file mode 100644 index 0000000..ead5ea0 --- /dev/null +++ b/benchmark/Benchmark/Trampoline.purs @@ -0,0 +1,3 @@ +module Benchmark.Trampoline (module Control.Monad.Trampoline) where + +import Control.Monad.Trampoline diff --git a/src/Control/Comonad/Cofree.purs b/src/Control/Comonad/Cofree.purs index 3167493..792a639 100644 --- a/src/Control/Comonad/Cofree.purs +++ b/src/Control/Comonad/Cofree.purs @@ -3,7 +3,8 @@ module Control.Comonad.Cofree ( Cofree , deferCofree - , mkCofree, (:<) + , mkCofree + , (:<) , head , tail , hoistCofree @@ -14,6 +15,7 @@ module Control.Comonad.Cofree ) where import Prelude + import Control.Alternative (class Alternative, (<|>), empty) import Control.Comonad (class Comonad, extract) import Control.Extend (class Extend) diff --git a/src/Control/Monad/Free.purs b/src/Control/Monad/Free.purs index 8ec8ccd..49fb44e 100644 --- a/src/Control/Monad/Free.purs +++ b/src/Control/Monad/Free.purs @@ -6,6 +6,9 @@ module Control.Monad.Free , hoistFree , foldFree , substFree + , interpret + , interpretRec + , run , runFree , runFreeM , resume @@ -17,41 +20,30 @@ import Prelude import Control.Apply (lift2) import Control.Monad.Rec.Class (class MonadRec, Step(..), tailRecM) import Control.Monad.Trans.Class (class MonadTrans) - -import Data.CatList (CatList, empty, snoc, uncons) import Data.Either (Either(..)) import Data.Eq (class Eq1, eq1) +import Data.Exists (Exists, mkExists, runExists) import Data.Foldable (class Foldable, foldMap, foldl, foldr) -import Data.Maybe (Maybe(..)) import Data.Ord (class Ord1, compare1) import Data.Traversable (class Traversable, traverse) -import Data.Tuple (Tuple(..)) - +import Prim.TypeError (class Warn, Text) import Unsafe.Coerce (unsafeCoerce) --- | The free monad for a type constructor `f`. --- | --- | Implemented in the spirit of [Reflection without Remorse](http://okmij.org/ftp/Haskell/zseq.pdf), --- | the free monad is represented using a sequential data structure in --- | order to overcome the quadratic complexity of left-associated binds --- | and traversal through the free monad structure. -data Free f a = Free (FreeView f Val Val) (CatList (ExpF f)) - -newtype ExpF f = ExpF (Val -> Free f Val) +foreign import data UnsafeBoundValue :: Type -data FreeView f a b = Return a | Bind (f b) (b -> Free f a) +foreign import data UnsafeBoundF :: Type -> Type -data Val +-- | The free monad for a type constructor `f`. +data Free f a + = Pure a + | Bind (f UnsafeBoundValue) (FreeBinds f UnsafeBoundValue a) instance eqFree :: (Functor f, Eq1 f, Eq a) => Eq (Free f a) where eq x y = case resume x, resume y of Left fa, Left fb -> eq1 fa fb - Right a, Right b -> a == b + Right a, Right b -> eq a b _, _ -> false -instance eq1Free :: (Functor f, Eq1 f) => Eq1 (Free f) where - eq1 = eq - instance ordFree :: (Functor f, Ord1 f, Ord a) => Ord (Free f a) where compare x y = case resume x, resume y of Left fa, Left fb -> compare1 fa fb @@ -59,30 +51,32 @@ instance ordFree :: (Functor f, Ord1 f, Ord a) => Ord (Free f a) where _, Left _ -> GT Right a, Right b -> compare a b +instance eq1Free :: (Functor f, Eq1 f) => Eq1 (Free f) where + eq1 = eq + instance ord1Free :: (Functor f, Ord1 f, Ord a) => Ord1 (Free f) where compare1 = compare -instance freeFunctor :: Functor (Free f) where - map k f = pure <<< k =<< f +instance functorFree :: Functor (Free f) where + map f (Pure a) = Pure (f a) + map f (Bind a bs) = Bind a (Node (unsafeCoerce bs) (Leaf (Pure <<< unsafeCoerce f))) -instance freeBind :: Bind (Free f) where - bind (Free v s) k = Free v (snoc s (ExpF (unsafeCoerceBind k))) - where - unsafeCoerceBind :: forall a b. (a -> Free f b) -> Val -> Free f Val - unsafeCoerceBind = unsafeCoerce +instance applyFree :: Apply (Free f) where + apply = ap -instance freeApplicative :: Applicative (Free f) where - pure = fromView <<< Return +instance applicativeFree :: Applicative (Free f) where + pure = Pure -instance freeApply :: Apply (Free f) where - apply = ap +instance bindFree :: Bind (Free f) where + bind (Pure a) k = k a + bind (Bind a bs) k = Bind a (Node (unsafeCoerce bs) (Leaf (unsafeCoerce k))) -instance freeMonad :: Monad (Free f) +instance monadFree :: Monad (Free f) -instance freeMonadTrans :: MonadTrans Free where +instance monadTransFree :: MonadTrans Free where lift = liftF -instance freeMonadRec :: MonadRec (Free f) where +instance monadRecFree :: MonadRec (Free f) where tailRecM k a = k a >>= case _ of Loop b -> tailRecM k b Done r -> pure r @@ -93,11 +87,13 @@ instance foldableFree :: (Functor f, Foldable f) => Foldable (Free f) where go = resume >>> case _ of Left fa -> foldMap go fa Right a -> f a + foldl f = go where - go r = resume >>> case _ of + go r = resume >>> case _ of Left fa -> foldl go r fa Right a -> f r a + foldr f = go where go r = resume >>> case _ of @@ -110,6 +106,7 @@ instance traversableFree :: Traversable f => Traversable (Free f) where go = resume >>> case _ of Left fa -> join <<< liftF <$> traverse go fa Right a -> pure <$> f a + sequence tma = traverse identity tma instance semigroupFree :: Semigroup a => Semigroup (Free f a) where @@ -117,129 +114,153 @@ instance semigroupFree :: Semigroup a => Semigroup (Free f a) where instance monoidFree :: Monoid a => Monoid (Free f a) where mempty = pure mempty - + +data FreeView f a b + = PureView a + | BindView (f b) (b -> Free f a) + +data FreeBinds f a b + = Leaf (a -> Free f b) + | Node (FreeBinds f a UnsafeBoundValue) (FreeBinds f UnsafeBoundValue b) + | Hoist (UnsafeBoundF ~> f) (FreeBinds UnsafeBoundF a b) + +data FreeCons f a b + = FreeCons (a -> Free f UnsafeBoundValue) (FreeBinds f UnsafeBoundValue b) + -- | Lift an impure value described by the generating type constructor `f` into -- | the free monad. -liftF :: forall f. f ~> Free f -liftF f = fromView (Bind (unsafeCoerceF f) (pure <<< unsafeCoerceVal)) - where - unsafeCoerceF :: forall a. f a -> f Val - unsafeCoerceF = unsafeCoerce - - unsafeCoerceVal :: forall a. Val -> a - unsafeCoerceVal = unsafeCoerce +liftF :: forall f a. f a -> Free f a +liftF f = Bind (unsafeCoerce f) (unsafeCoerce (Leaf Pure)) -- | Add a layer. wrap :: forall f a. f (Free f a) -> Free f a -wrap f = fromView (Bind (unsafeCoerceF f) unsafeCoerceVal) - where - unsafeCoerceF :: forall b. f (Free f b) -> f Val - unsafeCoerceF = unsafeCoerce +wrap f = Bind (unsafeCoerce f) (unsafeCoerce (Leaf \a -> a)) - unsafeCoerceVal :: forall b. Val -> Free f b - unsafeCoerceVal = unsafeCoerce - --- | Suspend a value given the applicative functor `f` into the free monad. -suspendF :: forall f. Applicative f => Free f ~> Free f + -- | Suspend a value given the applicative functor `f` into the free monad. +suspendF :: forall f a. Applicative f => Free f a -> Free f a suspendF f = wrap (pure f) -- | Use a natural transformation to change the generating type constructor of a -- | free monad. hoistFree :: forall f g. (f ~> g) -> Free f ~> Free g -hoistFree k = substFree (liftF <<< k) +hoistFree nat = case _ of + Pure a -> Pure a + Bind f k -> Bind (nat f) (Hoist (unsafeCoerce nat) (unsafeCoerce k)) + +-- | Run a free monad with a natural transformation from the type constructor `f` +-- | to the monad `m`, which can be some other Free monad. If you need tail +-- | recursion for stack safety, see `interpretRec`. +interpret :: forall f m a. Monad m => (f ~> m) -> Free f a -> m a +interpret next = go where go = resume' (\f k -> next f >>= k >>> go) pure + +-- | DEPRECATED: Use `interpret` instead. +-- | +-- | Like `foldFree` or `interpretRec` but for folding into some other Free +-- | monad without the overhead that `MonadRec` incurs. +substFree + :: forall f g + . Warn (Text "Deprecated: Use `interpret` instead.") + => (f ~> Free g) + -> Free f + ~> Free g +substFree = interpret -- | Run a free monad with a natural transformation from the type constructor `f` -- | to the tail-recursive monad `m`. See the `MonadRec` type class for more -- | details. -foldFree :: forall f m. MonadRec m => (f ~> m) -> Free f ~> m -foldFree k = tailRecM go - where - go :: forall a. Free f a -> m (Step (Free f a) a) - go f = case toView f of - Return a -> Done <$> pure a - Bind g i -> (Loop <<< i) <$> k g - --- | Like `foldFree`, but for folding into some other Free monad without the --- | overhead that `MonadRec` incurs. -substFree :: forall f g. (f ~> Free g) -> Free f ~> Free g -substFree k = go +interpretRec :: forall f m a. MonadRec m => (f ~> m) -> Free f a -> m a +interpretRec nat = tailRecM go <<< view where - go :: Free f ~> Free g - go f = case toView f of - Return a -> pure a - Bind g i -> k g >>= go <$> i + go = runExists case _ of + PureView a -> pure $ Done a + BindView f k -> Loop <<< view <<< k <$> nat f + +-- | DEPRECATED: Use `interpretRec` instead. +-- | +-- | Run a free monad with a natural transformation from the type constructor `f` +-- | to the tail-recursive monad `m`. See the `MonadRec` type class for more +-- | details. +foldFree + :: forall f m + . Warn (Text "Deprecated: Use `interpretRec` instead.") + => MonadRec m + => (f ~> m) + -> Free f + ~> m +foldFree = interpretRec + +-- | Run a free monad with a function mapping a functor `f` to a monad `m`. +run :: forall f m a. Functor f => Monad m => (f (Free f a) -> m (Free f a)) -> Free f a -> m a +run next = go where go = resume' (\f k -> next (k <$> f) >>= go) pure -- | Run a free monad with a function that unwraps a single layer of the functor -- | `f` at a time. runFree :: forall f a. Functor f => (f (Free f a) -> Free f a) -> Free f a -> a -runFree k = go +runFree next = go where go :: Free f a -> a - go f = case toView f of - Return a -> a - Bind g i -> go (k (i <$> g)) + go x = case unsafeCoerce (view x) :: FreeView f a UnsafeBoundValue of + PureView a -> a + BindView f k -> go (next (k <$> f)) -- | Run a free monad with a function mapping a functor `f` to a tail-recursive -- | monad `m`. See the `MonadRec` type class for more details. -runFreeM - :: forall f m a - . Functor f - => MonadRec m - => (f (Free f a) -> m (Free f a)) - -> Free f a - -> m a -runFreeM k = tailRecM go +runFreeM :: forall f m a. Functor f => MonadRec m => (f (Free f a) -> m (Free f a)) -> Free f a -> m a +runFreeM next = tailRecM go <<< view where - go :: Free f a -> m (Step (Free f a) a) - go f = case toView f of - Return a -> Done <$> pure a - Bind g i -> Loop <$> k (i <$> g) + go = runExists case _ of + PureView a -> pure $ Done a + BindView f k -> Loop <<< view <$> next (k <$> f) -- | Unwraps a single layer of the functor `f`. -resume - :: forall f a - . Functor f - => Free f a - -> Either (f (Free f a)) a -resume = resume' (\g i -> Left (i <$> g)) Right - --- | Unwraps a single layer of `f`, providing the continuation. +resume :: forall f a. Functor f => Free f a -> Either (f (Free f a)) a +resume = resume' (\g i -> Left (map i g)) Right + + -- | Unwraps a single layer of `f`, providing the continuation. resume' :: forall f a r . (forall b. f b -> (b -> Free f a) -> r) -> (a -> r) -> Free f a -> r -resume' k j f = case toView f of - Return a -> j a - Bind g i -> k g i - -fromView :: forall f a. FreeView f a Val -> Free f a -fromView f = Free (unsafeCoerceFreeView f) empty +resume' bind' pure' = case _ of + Pure a -> pure' a + Bind a bs -> bind' a (go1 bs) where - unsafeCoerceFreeView :: FreeView f a Val -> FreeView f Val Val - unsafeCoerceFreeView = unsafeCoerce - -toView :: forall f a. Free f a -> FreeView f a Val -toView (Free v s) = - case v of - Return a -> - case uncons s of - Nothing -> - Return (unsafeCoerceVal a) - Just (Tuple h t) -> - toView (unsafeCoerceFree (concatF ((runExpF h) a) t)) - Bind f k -> - Bind f (\a -> unsafeCoerceFree (concatF (k a) s)) + go1 :: forall x y. FreeBinds f x y -> x -> Free f y + go1 bs x = case bs of + Leaf k -> k x + Node l r -> case uncons l r of + FreeCons k bs' -> case k x of + Pure a -> go1 bs' a + Bind a bs'' -> Bind a (Node bs'' bs') + Hoist nat bs' -> + go2 nat bs' x + + go2 :: forall g x y. (UnsafeBoundF ~> g) -> FreeBinds UnsafeBoundF x y -> x -> Free g y + go2 nat bs x = case bs of + Leaf k -> hoistFree nat (k x) + Node l r -> case uncons l r of + FreeCons k bs' -> case k x of + Pure a -> go2 nat bs' a + Bind a bs'' -> Bind (nat a) (Hoist nat (Node bs'' bs')) + Hoist nat' bs' -> + go2 (nat <<< nat') bs' x + +uncons :: forall f a b x. FreeBinds f a x -> FreeBinds f x b -> FreeCons f a b +uncons = go1 where - concatF :: Free f Val -> CatList (ExpF f) -> Free f Val - concatF (Free v' l) r = Free v' (l <> r) - - runExpF :: ExpF f -> (Val -> Free f Val) - runExpF (ExpF k) = k - - unsafeCoerceFree :: Free f Val -> Free f a - unsafeCoerceFree = unsafeCoerce - - unsafeCoerceVal :: Val -> a - unsafeCoerceVal = unsafeCoerce + go1 :: forall a' b' x'. FreeBinds f a' x' -> FreeBinds f x' b' -> FreeCons f a' b' + go1 l r = case l of + Leaf k -> FreeCons (unsafeCoerce k) (unsafeCoerce r) + Node l' r' -> go1 l' (Node (unsafeCoerce r') (unsafeCoerce r)) + Hoist nat l' -> go2 nat l' r + + go2 :: forall g a' b' x'. (UnsafeBoundF ~> g) -> FreeBinds UnsafeBoundF a' x' -> FreeBinds g x' b' -> FreeCons g a' b' + go2 nat l r = case l of + Leaf k -> FreeCons (hoistFree nat <$> unsafeCoerce k) (unsafeCoerce r) + Node l' r' -> go2 nat l' (Node (Hoist nat (unsafeCoerce r')) (unsafeCoerce r)) + Hoist nat' n -> go2 (nat <<< nat') n r + +view :: forall f a. Free f a -> Exists (FreeView f a) +view = resume' (\a b -> mkExists (BindView a b)) (mkExists <<< PureView) diff --git a/src/Control/Monad/Trampoline.purs b/src/Control/Monad/Trampoline.purs index 6634ca2..44d3306 100644 --- a/src/Control/Monad/Trampoline.purs +++ b/src/Control/Monad/Trampoline.purs @@ -13,7 +13,6 @@ import Prelude import Control.Monad.Free (Free, liftF, runFree) - -- | The `Trampoline` monad -- | -- | A computation of type `Trampoline a` consists of zero or more lazy diff --git a/test/Test/Control/Monad/Free/Coproduct.purs b/test/Test/Control/Monad/Free/Coproduct.purs index e65826b..1e536b1 100644 --- a/test/Test/Control/Monad/Free/Coproduct.purs +++ b/test/Test/Control/Monad/Free/Coproduct.purs @@ -2,7 +2,7 @@ module Test.Control.Monad.Free.Coproduct where import Prelude -import Control.Monad.Free (Free, liftF, hoistFree, foldFree) +import Control.Monad.Free (Free, hoistFree, interpret, liftF) import Data.Functor.Coproduct (Coproduct, coproduct, left, right) import Effect (Effect) import Effect.Console (log) @@ -57,7 +57,7 @@ tN :: TF ~> Effect tN = coproduct teletype1N $ coproduct teletype2N teletype3N run :: T ~> Effect -run = foldFree tN +run = interpret tN main :: Effect Unit main = run u diff --git a/test/Test/Control/Monad/Free/Stratified.purs b/test/Test/Control/Monad/Free/Stratified.purs index 3cb0689..4d1a1c3 100644 --- a/test/Test/Control/Monad/Free/Stratified.purs +++ b/test/Test/Control/Monad/Free/Stratified.purs @@ -2,7 +2,7 @@ module Test.Control.Monad.Free.Stratified where import Prelude -import Control.Monad.Free (Free, foldFree, liftF) +import Control.Monad.Free (Free, interpret, liftF) import Effect (Effect) import Effect.Console (log) @@ -21,7 +21,7 @@ getLine = liftF $ GetLine identity -- | Interpreter for `Teletype`, producing an effectful output runTeletype :: Teletype ~> Effect -runTeletype = foldFree go +runTeletype = interpret go where go :: TeletypeF ~> Effect go (PutStrLn s next) = log s $> next @@ -45,7 +45,7 @@ farewell = liftF $ Farewell unit -- | the `Greet` case - we're expanding one `InitialF` action into 3 `TeletypeF` -- | actions). runInitial :: Initial ~> Teletype -runInitial initial = foldFree go initial +runInitial initial = interpret go initial where go :: InitialF ~> Teletype go (Greet k) = do diff --git a/test/Test/Control/Monad/Free/Teletype.purs b/test/Test/Control/Monad/Free/Teletype.purs index 469b3b0..34ac9fd 100644 --- a/test/Test/Control/Monad/Free/Teletype.purs +++ b/test/Test/Control/Monad/Free/Teletype.purs @@ -2,9 +2,9 @@ module Test.Control.Monad.Free.Teletype where import Prelude +import Control.Monad.Free (Free, interpret, liftF) import Effect (Effect) import Effect.Console (log) -import Control.Monad.Free (Free, foldFree, liftF) data TeletypeF a = PutStrLn String a | GetLine (String -> a) @@ -21,7 +21,7 @@ teletypeN (PutStrLn s a) = const a <$> log s teletypeN (GetLine k) = pure (k "fake input") run :: Teletype ~> Effect -run = foldFree teletypeN +run = interpret teletypeN echo :: Teletype String echo = do