|
| 1 | +module Benchmark.Free0df59c5 |
| 2 | + ( Free(..), GosubF() |
| 3 | + , FreeC(..) |
| 4 | + , MonadFree, wrap |
| 5 | + , Natural() |
| 6 | + , liftF, liftFI, liftFC, liftFCI |
| 7 | + , pureF, pureFC |
| 8 | + , mapF, mapFC |
| 9 | + , bindF, bindFC |
| 10 | + , injF, injFC |
| 11 | + , runFree |
| 12 | + , runFreeM |
| 13 | + , runFreeC |
| 14 | + , runFreeCM |
| 15 | + ) where |
| 16 | + |
| 17 | +import Prelude |
| 18 | + |
| 19 | +import Data.Exists |
| 20 | + |
| 21 | +import Control.Monad.Trans |
| 22 | +import Control.Monad.Eff |
| 23 | +import Control.Monad.Rec.Class |
| 24 | + |
| 25 | +import Data.Identity |
| 26 | +import Data.Coyoneda |
| 27 | +import Data.Either |
| 28 | +import Data.Function |
| 29 | +import Data.Maybe |
| 30 | +import Data.Inject (Inject, inj) |
| 31 | + |
| 32 | +type Natural f g = forall a. f a -> g a |
| 33 | + |
| 34 | +newtype GosubF f a i = GosubF { a :: Unit -> Free f i, f :: i -> Free f a } |
| 35 | + |
| 36 | +gosub :: forall f a i. (Unit -> Free f i) -> (i -> Free f a) -> Free f a |
| 37 | +gosub a f = Gosub $ mkExists $ GosubF { a: a, f: f} |
| 38 | + |
| 39 | +-- | The free `Monad` for a `Functor`. |
| 40 | +-- | |
| 41 | +-- | The implementation defers the evaluation of monadic binds so that it |
| 42 | +-- | is safe to use monadic tail recursion, for example. |
| 43 | +data Free f a = Pure a |
| 44 | + | Free (f (Free f a)) |
| 45 | + | Gosub (Exists (GosubF f a)) |
| 46 | + |
| 47 | +-- | The free `Monad` for an arbitrary type constructor. |
| 48 | +type FreeC f = Free (Coyoneda f) |
| 49 | + |
| 50 | +-- | The `MonadFree` class provides the `wrap` function, which lifts |
| 51 | +-- | actions described by a generating functor into a monad. |
| 52 | +-- | |
| 53 | +-- | The canonical instance of `MonadFree f` is `Free f`. |
| 54 | +class MonadFree f m where |
| 55 | + wrap :: forall a. f (m a) -> m a |
| 56 | + |
| 57 | +instance functorFree :: (Functor f) => Functor (Free f) where |
| 58 | + map f (Pure a) = Pure (f a) |
| 59 | + map f g = liftA1 f g |
| 60 | + |
| 61 | +instance applyFree :: (Functor f) => Apply (Free f) where |
| 62 | + apply = ap |
| 63 | + |
| 64 | +instance applicativeFree :: (Functor f) => Applicative (Free f) where |
| 65 | + pure = Pure |
| 66 | + |
| 67 | +instance bindFree :: (Functor f) => Bind (Free f) where |
| 68 | + bind (Gosub g) k = runExists (\(GosubF v) -> gosub v.a (\x -> gosub (\unit -> v.f x) k)) g |
| 69 | + bind a k = gosub (\unit -> a) k |
| 70 | + |
| 71 | +instance monadFree :: (Functor f) => Monad (Free f) |
| 72 | + |
| 73 | +instance monadTransFree :: MonadTrans Free where |
| 74 | + lift f = Free $ do |
| 75 | + a <- f |
| 76 | + return (Pure a) |
| 77 | + |
| 78 | +instance monadFreeFree :: (Functor f) => MonadFree f (Free f) where |
| 79 | + wrap = Free |
| 80 | + |
| 81 | +instance monadRecFree :: (Functor f) => MonadRec (Free f) where |
| 82 | + tailRecM f u = f u >>= \o -> case o of |
| 83 | + Left a -> tailRecM f a |
| 84 | + Right b -> pure b |
| 85 | + |
| 86 | +-- | Lift an action described by the generating functor `f` into the monad `m` |
| 87 | +-- | (usually `Free f`). |
| 88 | +liftF :: forall f m a. (Functor f, Monad m, MonadFree f m) => f a -> m a |
| 89 | +liftF = wrap <<< map pure |
| 90 | + |
| 91 | +-- | Lift an action described by the generating type constructor `f` into |
| 92 | +-- | `Free g` using `Inject` to go from `f` to `g`. |
| 93 | +liftFI :: forall f g a. (Inject f g, Functor g) => f a -> Free g a |
| 94 | +liftFI fa = liftF (inj fa :: g a) |
| 95 | + |
| 96 | +-- | Lift an action described by the generating type constructor `f` into the monad |
| 97 | +-- | `FreeC f`. |
| 98 | +liftFC :: forall f a. f a -> FreeC f a |
| 99 | +liftFC = liftF <<< liftCoyoneda |
| 100 | + |
| 101 | +-- | Lift an action described by the generating type constructor `f` into |
| 102 | +-- | `FreeC g` using `Inject` to go from `f` to `g`. |
| 103 | +liftFCI :: forall f g a. (Inject f g) => f a -> FreeC g a |
| 104 | +liftFCI fa = liftFC (inj fa :: g a) |
| 105 | + |
| 106 | +-- | An implementation of `pure` for the `Free` monad. |
| 107 | +pureF :: forall f a. (Applicative f) => a -> Free f a |
| 108 | +pureF = Free <<< pure <<< Pure |
| 109 | + |
| 110 | +-- | An implementation of `pure` for the `FreeC` monad. |
| 111 | +pureFC :: forall f a. (Applicative f) => a -> FreeC f a |
| 112 | +pureFC = liftFC <<< pure |
| 113 | + |
| 114 | +-- | Use a natural transformation to change the generating functor of a `Free` monad. |
| 115 | +mapF :: forall f g a. (Functor f, Functor g) => Natural f g -> Free f a -> Free g a |
| 116 | +mapF t fa = either (\s -> Free <<< t $ mapF t <$> s) Pure (resume fa) |
| 117 | + |
| 118 | +-- | Use a natural transformation to change the generating type constructor of |
| 119 | +-- | a `FreeC` monad to another functor. |
| 120 | +mapFC :: forall f g a. (Functor g) => Natural f g -> FreeC f a -> Free g a |
| 121 | +mapFC t = mapF (liftCoyonedaTF t) |
| 122 | + |
| 123 | +-- | Use a natural transformation to interpret one `Free` monad as another. |
| 124 | +bindF :: forall f g a. (Functor f, Functor g) => Free f a -> Natural f (Free g) -> Free g a |
| 125 | +bindF fa t = either (\m -> t m >>= \fa' -> bindF fa' t) Pure (resume fa) |
| 126 | + |
| 127 | +-- | Use a natural transformation to interpret a `FreeC` monad as a different |
| 128 | +-- | `Free` monad. |
| 129 | +bindFC :: forall f g a. (Functor g) => FreeC f a -> Natural f (Free g) -> Free g a |
| 130 | +bindFC fa t = bindF fa (liftCoyonedaTF t) |
| 131 | + |
| 132 | +-- | Embed computations in one `Free` monad as computations in the `Free` monad for |
| 133 | +-- | a coproduct type constructor. |
| 134 | +-- | |
| 135 | +-- | This construction allows us to write computations which are polymorphic in the |
| 136 | +-- | particular `Free` monad we use, allowing us to extend the functionality of |
| 137 | +-- | our monad later. |
| 138 | +injF :: forall f g a. (Functor f, Functor g, Inject f g) => Free f a -> Free g a |
| 139 | +injF = mapF inj |
| 140 | + |
| 141 | +-- | Embed computations in one `FreeC` monad as computations in the `FreeC` monad for |
| 142 | +-- | a coproduct type constructor. |
| 143 | +-- | |
| 144 | +-- | This construction allows us to write computations which are polymorphic in the |
| 145 | +-- | particular `Free` monad we use, allowing us to extend the functionality of |
| 146 | +-- | our monad later. |
| 147 | +injFC :: forall f g a. (Inject f g) => FreeC f a -> FreeC g a |
| 148 | +injFC = mapF (liftCoyonedaT inj) |
| 149 | + |
| 150 | +resume :: forall f a. (Functor f) => Free f a -> Either (f (Free f a)) a |
| 151 | +resume f = case f of |
| 152 | + Pure x -> Right x |
| 153 | + Free x -> Left x |
| 154 | + g -> case resumeGosub g of |
| 155 | + Left l -> Left l |
| 156 | + Right r -> resume r |
| 157 | + where |
| 158 | + resumeGosub :: Free f a -> Either (f (Free f a)) (Free f a) |
| 159 | + resumeGosub (Gosub g) = |
| 160 | + runExists (\(GosubF v) -> case v.a unit of |
| 161 | + Pure a -> Right (v.f a) |
| 162 | + Free t -> Left ((\h -> h >>= v.f) <$> t) |
| 163 | + Gosub h -> runExists (\(GosubF w) -> Right (w.a unit >>= (\z -> w.f z >>= v.f))) h) g |
| 164 | + |
| 165 | +-- | `runFree` runs a computation of type `Free f a`, using a function which unwraps a single layer of |
| 166 | +-- | the functor `f` at a time. |
| 167 | +runFree :: forall f a. (Functor f) => (f (Free f a) -> Free f a) -> Free f a -> a |
| 168 | +runFree fn = runIdentity <<< runFreeM (Identity <<< fn) |
| 169 | + |
| 170 | +-- | `runFreeM` runs a compuation of type `Free f a` in any `Monad` which supports tail recursion. |
| 171 | +-- | See the `MonadRec` type class for more details. |
| 172 | +runFreeM :: forall f m a. (Functor f, MonadRec m) => (f (Free f a) -> m (Free f a)) -> Free f a -> m a |
| 173 | +runFreeM fn = tailRecM \f -> |
| 174 | + case resume f of |
| 175 | + Left fs -> Left <$> fn fs |
| 176 | + Right a -> return (Right a) |
| 177 | + |
| 178 | +-- | `runFreeC` is the equivalent of `runFree` for type constructors transformed with `Coyoneda`, |
| 179 | +-- | hence we have no requirement that `f` be a `Functor`. |
| 180 | +runFreeC :: forall f a. (forall a. f a -> a) -> FreeC f a -> a |
| 181 | +runFreeC nat = runIdentity <<< runFreeCM (Identity <<< nat) |
| 182 | + |
| 183 | +-- | `runFreeCM` is the equivalent of `runFreeM` for type constructors transformed with `Coyoneda`, |
| 184 | +-- | hence we have no requirement that `f` be a `Functor`. |
| 185 | +runFreeCM :: forall f m a. (MonadRec m) => Natural f m -> FreeC f a -> m a |
| 186 | +runFreeCM nat = runFreeM (liftCoyonedaTF nat) |
0 commit comments