├── Setup.hs ├── .gitignore ├── ChangeLog.md ├── README.md ├── freer-church.cabal ├── LICENSE ├── tests └── example.hs └── src └── Control └── Monad └── Freer └── Church.hs /Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | dist/ 3 | new-dist/ 4 | .cabal-sandbox/ 5 | cabal.sandbox.config 6 | -------------------------------------------------------------------------------- /ChangeLog.md: -------------------------------------------------------------------------------- 1 | # Revision history for freer-church 2 | 3 | ## 0.0 -- 2016-10-26 4 | 5 | * First version. 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Church-encoded Freer Monad # 2 | 3 | This Oleg's [Freer monad](http://okmij.org/ftp/Computation/free-monad.html) but Church-encoded. 4 | 5 | - Because it's the Freer monad, `FFC g` is a Monad for any `g` even if it isn't a functor. 6 | - Because it's Church-encoded, it reassociates left-nested binds: `(m >>= f) >>= g` immediately reassociates to `m >>= \x -> f x >>= g` 7 | 8 | 9 | ## It's just continuations ## 10 | 11 | Start with Oleg's "Freer monad" 12 | 13 | ```haskell 14 | data Freer g a where 15 | FPure :: a -> Freer g a 16 | FImpure :: g x -> (x -> Freer g a) -> Freer g a 17 | ``` 18 | 19 | Church encode it to get 20 | 21 | ```haskell 22 | data FFC g a = 23 | FFC { unFFC :: forall r . (a -> r) -> (forall x . g x -> (x -> r) -> r) -> r } 24 | ``` 25 | 26 | Now flip the two arguments around and note that [Cont](http://hackage.haskell.org/package/transformers-0.5.2.0/docs/Control-Monad-Trans-Cont.html#t:Cont) t b = (b -> t) -> t 27 | 28 | ```haskell 29 | data FFC g a = 30 | FFC { unFFC :: forall r . (forall x . g x -> Cont r x) -> Cont r a } 31 | ``` 32 | 33 | So, the Freer monad is just an interpreter for 'g' into the continuation monad. 34 | -------------------------------------------------------------------------------- /freer-church.cabal: -------------------------------------------------------------------------------- 1 | name: freer-church 2 | version: 0.0 3 | synopsis: Church-encoded Freer monad 4 | -- description: 5 | homepage: https://github.com/lambdageek/freer-church 6 | license: BSD3 7 | license-file: LICENSE 8 | author: Aleksey Kliger 9 | maintainer: aleksey@lambdageek.org 10 | -- copyright: 11 | category: Control 12 | build-type: Simple 13 | extra-source-files: ChangeLog.md 14 | cabal-version: >=1.10 15 | 16 | library 17 | exposed-modules: Control.Monad.Freer.Church 18 | -- other-modules: 19 | -- other-extensions: 20 | build-depends: base >=4.8 && <5 21 | , transformers >= 0.5 && < 0.6 22 | hs-source-dirs: src 23 | default-language: Haskell2010 24 | ghc-options: -fno-max-relevant-binds 25 | 26 | test-suite example 27 | type: exitcode-stdio-1.0 28 | default-language: Haskell2010 29 | hs-source-dirs: tests 30 | main-is: example.hs 31 | build-depends: base >= 4.9 && < 5 32 | , free >= 4.12 33 | , freer-church 34 | , transformers >= 0.5 && < 0.6 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Aleksey Kliger 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | 16 | * Neither the name of Aleksey Kliger nor the names of other 17 | contributors may be used to endorse or promote products derived 18 | from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /tests/example.hs: -------------------------------------------------------------------------------- 1 | {-# language GADTs, RankNTypes, GeneralizedNewtypeDeriving #-} 2 | 3 | import Control.Monad.Free.Church (F (..), retract, hoistF) 4 | import Control.Monad.Freer.Church 5 | 6 | import Control.Applicative (Alternative (..)) 7 | import Control.Monad (MonadPlus(..), unless, replicateM_) 8 | import Control.Monad.Trans.State 9 | import Control.Monad.Trans.Except 10 | import Control.Monad.Trans.Class (lift) 11 | 12 | import Data.Functor.Identity 13 | import Data.Function (on) 14 | 15 | -- | The empty type constructor with no values. 16 | data Empty a 17 | 18 | -- | Ex falso quodlibet. 19 | vacuous :: Empty a -> b 20 | vacuous emp = emp `seq` vacuous emp 21 | 22 | instance Functor Empty where 23 | fmap _f emp = vacuous emp 24 | 25 | -- | The freer monad of the empty 'Functor' is the 'Identity' monad 26 | interpEmpty :: FFC Empty a -> Identity a 27 | interpEmpty = retractFFC . foist phi 28 | where 29 | phi :: Empty x -> Identity x 30 | phi emp = vacuous emp 31 | 32 | f :: Monad m => Int -> m Int 33 | f 0 = return 1 34 | f 1 = return 1 35 | f n = do 36 | i <- f (n - 1) 37 | j <- f (n - 2) 38 | return (i + j) 39 | 40 | data Const b a = Const b 41 | 42 | instance Functor (Const b) where 43 | fmap _f (Const b) = Const b 44 | 45 | interpConst :: FFC (Const b) a -> Either b a 46 | interpConst = retractFFC . foist phi 47 | where 48 | phi :: Const b x -> Either b x 49 | phi (Const b) = Left b 50 | 51 | raiseConst :: b -> FFC (Const b) a 52 | raiseConst b = eta (Const b) 53 | 54 | data Cont a = Cont { runCont :: forall r . (a -> r) -> r } 55 | 56 | instance Functor Cont where 57 | fmap f (Cont c) = Cont (\k -> c (k . f)) 58 | 59 | instance Applicative Cont where 60 | pure = retCont 61 | mf <*> mx = mf >>= \f -> mx >>= (return . f) 62 | 63 | instance Monad Cont where 64 | return = retCont 65 | (Cont cx) >>= f = Cont (\k -> cx (\x -> runCont (f x) k)) 66 | 67 | retCont :: a -> Cont a 68 | retCont a = Cont (\k -> k a) 69 | 70 | interpretIdentity :: FFC Identity a -> Cont a 71 | interpretIdentity = retractFFC . foist phi 72 | where 73 | phi :: Identity x -> Cont x 74 | phi (Identity x) = retCont x 75 | 76 | contCont :: (forall r . (a -> r) -> r) -> FFC Identity a 77 | contCont k = eta (k Identity) 78 | 79 | data Teletype a where 80 | ReadTTY :: Teletype Char 81 | WriteTTY :: Char -> Teletype () 82 | 83 | data TeleF next where 84 | ReadF :: (Char -> next) -> TeleF next 85 | WriteF :: Char -> next -> TeleF next 86 | 87 | instance Functor TeleF where 88 | fmap f (ReadF k) = ReadF (f . k) 89 | fmap f (WriteF c k) = WriteF c (f k) 90 | 91 | teleTo :: FFC Teletype a -> F TeleF a 92 | teleTo = retractFFC . foist phi 93 | -- F (\ar telek -> p ar (\tty k -> case tty of 94 | -- ReadTTY -> telek (ReadF k) 95 | -- WriteTTY c -> telek (WriteF c (k ())))) 96 | where 97 | phi :: Teletype x -> F TeleF x 98 | phi ReadTTY = F (\ar telek -> telek (ReadF ar)) 99 | phi (WriteTTY c) = F (\ar telek -> telek (WriteF c (ar ()))) 100 | 101 | 102 | teleFrom :: F TeleF a -> FFC Teletype a 103 | teleFrom = retract . hoistF phi 104 | -- FFC (\pur imp -> q pur (\telek -> case telek of 105 | -- ReadF k -> imp ReadTTY k 106 | -- WriteF c k -> imp (WriteTTY c) (\() -> k))) 107 | where 108 | phi :: TeleF x -> FFC Teletype x 109 | phi (ReadF k) = fimpure ReadTTY (fpure . k) 110 | phi (WriteF c k) = fimpure (WriteTTY c) (\() -> pure k) 111 | 112 | 113 | ttyIO :: FFC Teletype a -> IO a 114 | ttyIO = retractFFC . foist phi 115 | -- p return (\tty -> case tty of 116 | -- ReadTTY -> \k -> getChar >>= k 117 | -- WriteTTY c -> \k -> putChar c >> k ()) 118 | where 119 | phi :: Teletype x -> IO x 120 | phi ReadTTY = getChar 121 | phi (WriteTTY c) = putChar c 122 | 123 | newtype TapeIn = TapeIn String 124 | deriving (Show, Eq) 125 | newtype TapeOut = TapeOut ShowS 126 | 127 | mkTapeOut :: String -> TapeOut 128 | mkTapeOut = TapeOut . showString 129 | 130 | playOutTape :: TapeOut -> String 131 | playOutTape (TapeOut s) = s "" 132 | 133 | instance Eq TapeOut where 134 | (==) = (==) `on` playOutTape 135 | 136 | instance Show TapeOut where 137 | showsPrec _ = showString . playOutTape 138 | 139 | newtype Tapes a = Tapes { unTapes :: ExceptT () (State (TapeIn, TapeOut)) a } 140 | deriving (Functor, Applicative, Alternative, Monad, MonadPlus) 141 | 142 | runTapes :: Tapes a -> TapeIn -> (Maybe a, TapeIn, TapeOut) 143 | runTapes (Tapes m) tapeIn = case runState (runExceptT m) (tapeIn, TapeOut id) of 144 | (Left (), (tapeIn, tapeOut)) -> (Nothing, tapeIn, tapeOut) 145 | (Right a, (tapeIn, tapeOut)) -> (Just a, tapeIn, tapeOut) 146 | 147 | getTape :: Tapes Char 148 | getTape = Tapes $ do 149 | (tapeIn, tapeOut) <- lift get 150 | case tapeIn of 151 | TapeIn [] -> mzero 152 | TapeIn (c:cs) -> do 153 | lift $ put (TapeIn cs, tapeOut) 154 | return c 155 | 156 | putTape :: Char -> Tapes () 157 | putTape c = Tapes $ lift $ modify (\(tapeIn, TapeOut cs) -> (tapeIn, TapeOut (cs . showChar c))) 158 | 159 | 160 | ttyTape :: FFC Teletype a -> Tapes a 161 | ttyTape = retractFFC . foist phi -- (FFC p) = p pur imp 162 | where 163 | phi :: Teletype x -> Tapes x 164 | phi ReadTTY = getTape 165 | phi (WriteTTY c) = putTape c 166 | -- where 167 | -- pur :: a -> TapeIn -> (Maybe (a, TapeOut), TapeIn) 168 | -- pur = \x tape -> (Just (x, TapeOut []), tape) 169 | -- imp :: Teletype x -> (x -> TapeIn -> (Maybe (a, TapeOut), TapeIn)) -> TapeIn -> (Maybe (a, TapeOut), TapeIn) 170 | -- imp = \tty -> case tty of 171 | -- ReadTTY -> \ k tape -> case tape of 172 | -- TapeIn [] -> (Nothing, TapeIn []) 173 | -- TapeIn (c:cs) -> k c (TapeIn cs) 174 | -- WriteTTY c -> \k tape -> case k () tape of 175 | -- (Nothing, tapeIn) -> (Nothing, tapeIn) 176 | -- (Just (ans, TapeOut cs), tapeIn) -> (Just (ans, TapeOut (c:cs)), tapeIn) 177 | {-# INLINE ttyTape #-} 178 | 179 | readTTY :: FFC Teletype Char 180 | readTTY = eta ReadTTY 181 | 182 | writeTTY :: Char -> FFC Teletype () 183 | writeTTY = eta . WriteTTY 184 | 185 | echo :: Int -> FFC Teletype () 186 | echo n = replicateM_ n $ do 187 | c <- readTTY 188 | writeTTY c 189 | 190 | 191 | echo' :: Int -> FFC Teletype () 192 | echo' = teleFrom . teleTo . echo 193 | 194 | assertEq :: (Show a, Eq a) => a -> a -> IO () 195 | assertEq got want = 196 | unless (got == want) $ fail ("Expected: " ++ show want ++ "\nGot: " ++ show got) 197 | 198 | echoTape = ttyTape . echo 199 | echoTape' = ttyTape . echo' 200 | 201 | main = do 202 | assertEq (interpEmpty (f 10)) 89 203 | assertEq (runTapes (echoTape 2) (TapeIn "abcd")) (Just (), TapeIn "cd", mkTapeOut "ab") 204 | assertEq (runTapes (echoTape' 2) (TapeIn "abcd")) (Just (), TapeIn "cd", mkTapeOut "ab") 205 | -- ttyIO (echo 10) 206 | 207 | -------------------------------------------------------------------------------- /src/Control/Monad/Freer/Church.hs: -------------------------------------------------------------------------------- 1 | -- | Church encoded Freer monad 2 | -- 3 | -- Based on Oleg's Freer Monad but Chruch encoded. 4 | {-# language GADTs, RankNTypes #-} 5 | module Control.Monad.Freer.Church ( 6 | -- * Derivation 7 | -- $derivation 8 | 9 | -- * Definition 10 | FFC (..) 11 | , FFCT (..) 12 | -- * Operations 13 | , eta 14 | , eta' 15 | , fpure 16 | , fpure' 17 | , fimpure 18 | , fimpure' 19 | , foist 20 | , foistT 21 | , retractFFC 22 | , retractFFCT 23 | -- * Proofs 24 | -- $proofs 25 | ) where 26 | 27 | import Control.Monad.Trans.Cont 28 | import Control.Monad.Trans.Class 29 | 30 | -- $derivation 31 | -- 32 | -- Start with Oleg's "Freer monad" 33 | -- 34 | -- @ 35 | -- data Freer g a where 36 | -- FPure :: a -> Freer g a 37 | -- FImpure :: g x -> (x -> Freer g a) -> Freer g a 38 | -- @ 39 | -- 40 | -- Church encode it to get 41 | -- 42 | -- @ 43 | -- data FFC g a = 44 | -- FFC { unFFC :: forall r . (a -> r) -> (forall x . g x -> (x -> r) -> r) -> r } 45 | -- @ 46 | -- 47 | -- Now flip the two arguments around and note that @'Cont' t b = (b -> t) -> t@ 48 | -- 49 | -- @ 50 | -- data FFC g a = 51 | -- FFC { unFFC :: forall r . (forall x . g x -> Cont r x) -> Cont r a } 52 | -- @ 53 | -- 54 | -- So, the Freer monad is just an interpreter for 'g' into the continuation monad. 55 | 56 | -- | The Church-encoded Freer 'Monad'. For any @g@ (even if it isn't a 'Functor'!) @FFC g@ is a monad. 57 | -- 58 | -- 59 | -- Think of 'FFC' as if it were like @Freer@ 60 | -- 61 | -- @ 62 | -- data Freer g a where 63 | -- FPure :: a -> Freer g a 64 | -- FImpure :: g x -> (x -> Freer g a) -> Freer g a 65 | -- @ 66 | newtype FFC g a = 67 | FFC { unFFC :: forall r . (forall x . g x -> Cont r x) -> Cont r a } 68 | 69 | -- | Freer monad transformer. 70 | -- 71 | -- Unfolding the definition of 'ContT' this type is precisely 72 | -- 73 | newtype FFCT g m a = 74 | FFCT { unFFCT :: forall r . (forall x . g x -> ContT r m x) -> ContT r m a} 75 | 76 | runFFC :: FFC g a -> (a -> r) -> (forall x . g x -> (x -> r) -> r) -> r 77 | runFFC ma pur imp = runCont (unFFC ma (cont . imp)) pur 78 | 79 | runFFCT :: Monad m => FFCT g m a -> (a -> m r) -> (forall x . g x -> (x -> m r) -> m r) -> m r 80 | runFFCT tma mpur mimp = runContT (unFFCT tma (ContT . mimp)) mpur 81 | 82 | -- | It's a 'Functor' without a constraint on g 83 | instance Functor (FFC g) where 84 | fmap f = \ma -> FFC (\imp -> fmap f (unFFC ma imp)) 85 | {-# INLINE fmap #-} 86 | 87 | instance Functor (FFCT g m) where 88 | fmap f = \tma -> FFCT (\mimp -> fmap f (unFFCT tma mimp)) 89 | 90 | -- | Lift a pure value into the Freer monad 91 | fpure :: a -> FFC g a 92 | fpure = \a -> FFC (\imp -> pure a) 93 | {-# INLINE fpure #-} 94 | 95 | -- | Lift a pure value into a Freer monad transformer 96 | fpure' :: a -> FFCT g m a 97 | fpure' = \a -> FFCT (\mimp -> pure a) 98 | {-# INLINE fpure' #-} 99 | 100 | -- | Given an operation in @g@ and a continuation returning a monadic 101 | -- computation, sequence the continuation after the operation. 102 | fimpure :: g x -> (x -> FFC g a) -> FFC g a 103 | fimpure = \gx k -> FFC (\imp -> (imp gx) >>= \x -> unFFC (k x) imp) 104 | {-# INLINE fimpure #-} 105 | 106 | -- | Sequence an operation in @g@ to be followed by the continuation. 107 | fimpure' :: g x -> (x -> FFCT g m a) -> FFCT g m a 108 | fimpure' = \ gx k -> FFCT (\mimp -> (mimp gx) >>= \x -> unFFCT (k x) mimp) 109 | 110 | -- | Embed an operation of 'g' into the monad 111 | -- 112 | -- @ 113 | -- eta eff === fimpure eff fpure 114 | -- @ 115 | eta :: g a -> FFC g a 116 | eta = \eff -> FFC (\imp -> imp eff) 117 | {-# INLINE eta #-} 118 | -- proof: 119 | -- eta eff 120 | -- === FFC (\pur imp -> imp eff pur) by defn 121 | -- === FFC (\pur imp -> imp eff (\x -> pur x)) by eta expansion 122 | -- === FFC (\pur imp -> imp eff (\x -> unFFC (FFC (\pur' _ -> pur' x)) pur imp)) by defn & eta expansion 123 | -- === FFC (\pur imp -> imp eff (\x -> unFFC (fpure x) pur imp)) by defn 124 | -- === fimpure eff fpure by defn 125 | 126 | -- | Embed an operation of 'g' into the monad transformer 127 | eta' :: g a -> FFCT g m a 128 | eta' = \eff -> FFCT (\mimp -> mimp eff) 129 | {-# INLINE eta' #-} 130 | 131 | -- | It's an 'Applicative' without a constraint on g 132 | instance Applicative (FFC g) where 133 | pure = fpure 134 | {-# INLINE pure #-} 135 | (<*>) = \mf mx -> FFC (\imp -> unFFC mf imp <*> unFFC mx imp) 136 | -- \mf mx -> unFFC mf (unFFC mx (\x f -> (fpure (f x))) 137 | -- (\gx k f -> fimpure gx (\x -> (k x f)))) 138 | -- fimpure 139 | {-# INLINE (<*>) #-} 140 | 141 | instance Applicative (FFCT g m) where 142 | pure = fpure' 143 | (<*>) = \mf mx -> FFCT (\mimp -> unFFCT mf mimp <*> unFFCT mx mimp) 144 | 145 | 146 | -- | And it's a 'Monad' without constraints on 'g' 147 | instance Monad (FFC g) where 148 | return = fpure 149 | {-# INLINE return #-} 150 | (>>=) = \mx f -> FFC (\imp -> unFFC mx imp >>= \x -> unFFC (f x) imp) 151 | -- unFFC mx f fimpure 152 | {-# INLINE (>>=) #-} 153 | 154 | instance Monad (FFCT g m) where 155 | return = fpure' 156 | (>>=) = \mx f -> FFCT (\mimp -> unFFCT mx mimp >>= \x -> unFFCT (f x) mimp) 157 | 158 | instance MonadTrans (FFCT g) where 159 | lift m = FFCT (\mimp -> lift m) 160 | 161 | -- | Lift a natural transformation in Hask to a natural transformation on the free monads. 162 | foist :: (forall x . f x -> g x) -> FFC f a -> FFC g a 163 | foist phi = \ma -> -- unFFC ma return (fimpure . phi) 164 | FFC (\imp -> unFFC ma (imp . phi)) 165 | {-# INLINE foist #-} 166 | 167 | -- | Lift a natural transformation in Hask to a natural transformation on the free monads. 168 | foistT :: (forall x . f x -> g x) -> FFCT f m a -> FFCT g m a 169 | foistT phi = \ma -> FFCT (\mimp -> unFFCT ma (mimp . phi)) 170 | 171 | -- | If @m@ is a monad, we can interpret @FFC m@ in itself 172 | retractFFC :: Monad m => FFC m a -> m a 173 | retractFFC ma = runCont (unFFC ma (\mx -> cont (\f -> mx >>= f))) return 174 | {-# INLINE retractFFC #-} 175 | -- effects are interpreted as themselves: 176 | -- 177 | -- @ 178 | -- retractFFC (eff ma) === ma 179 | -- @ 180 | -- 181 | -- @ 182 | -- retractFFC (eff ma) 183 | -- === unFFC (FFC (\pur imp -> imp ma pur) return (>>=)) by defns 184 | -- === (>>=) ma return by beta 185 | -- === ma by right identity law 186 | -- @ 187 | -- 188 | -- and its a monad homomorphism 189 | -- 190 | -- @ 191 | -- retractFFC (return a) === return a 192 | -- @ 193 | -- 194 | -- @ 195 | -- unFFC (FFC (\pur _ -> pur a)) return (>>=) by defns 196 | -- === return a by beta 197 | -- @ 198 | -- 199 | -- @ 200 | -- retractFFC (m >>= f) === retractFFC m >>= retractFFC . f 201 | -- @ 202 | -- 203 | -- @ 204 | -- retractFFC (FFC (\pur imp -> unFFC m (\x -> unFFC (f x) pur imp) imp)) by defn (>>=) 205 | -- === unFFC (FFC (\pur imp -> unFFC m (\x -> unFFC (f x) pur imp) imp)) return (>>=) by defn retractFFC 206 | -- === unFFC m (\x -> unFFC (f x) return (>>=)) (>>=) by beta 207 | -- === 208 | -- === ??? 209 | -- === 210 | -- === unFFC m return (>>=) >>= \x -> unFFC (f x) return (>>=) by defn retractFFC 211 | -- retractFFC m >>= \x -> retractFFC (f x) 212 | -- @ 213 | -- 214 | -- stuck here. 215 | 216 | -- | Interpret the freer monad transformer in itself. 217 | retractFFCT :: (MonadTrans t, Monad (t m), Monad m) => FFCT (t m) m a -> t m a 218 | retractFFCT ma = join . lift $ runContT (unFFCT ma (\tmx -> ContT (\kmtm -> return $ tmx >>= (join . lift . kmtm)))) (return . return) 219 | where 220 | join :: Monad m => m (m a) -> m a 221 | join mmx = mmx >>= id 222 | 223 | -- $proofs 224 | -- 225 | -- == Functor law 226 | -- 227 | -- It's a real functor. (id law left as exercise) 228 | -- 229 | -- === Composition 230 | -- 231 | -- @fmap f . fmap g === fmap (f . g)@ 232 | -- 233 | -- @ 234 | -- fmap f (fmap g (FFC p)) 235 | -- === fmap f (FFC (\\pur imp -> p (pur . g) imp)) by defn 236 | -- === FFC (\\pur' imp' -> (\\pur imp -> p (pur . g) imp) (pur' . f) imp') by defn 237 | -- === FFC (\\pur' imp' -> p ((pur' . f) . g) imp') by beta 238 | -- === FFC (\\pur' imp' -> p (pur' . (f . g)) imp') by assoc-compose 239 | -- === fmap (f . g) (FFC p) by defn 240 | -- @ 241 | -- 242 | -- == Applicative Laws 243 | -- 244 | -- === Identity 245 | -- @ 246 | -- pure id \<*\> v === v 247 | -- @ 248 | -- 249 | -- @ 250 | -- pure id \<*\> (FFC vp) 251 | -- === (FFC (\\pur _ -> pur id)) \<*\> (FFC vp) by defn pure 252 | -- === FFC (\\pur' imp' -> (\\pur _ -> pur id) (\\f -> vp (pur' . f) imp') imp') by defn (\<*\>) 253 | -- === FFC (\\pur' imp' -> (\\f -> vp (pur' . f) imp') id) by beta 254 | -- === FFC (\\pur' imp' -> vp (pur' . id) imp') by beta 255 | -- === FFC (\\pur' imp' -> vp pur' imp') by compose-id 256 | -- === FFC vp by eta 257 | -- @ 258 | -- 259 | -- === Homomorphism 260 | -- 261 | -- @ 262 | -- pure f \<*\> pure x === pure (f x) 263 | -- @ 264 | -- 265 | -- @ 266 | -- pure f <*> pure x 267 | -- === FFC (\\pur _ -> pur f) <*> FFC (\\pur' _-> pur' x) by defn 268 | -- === FFC (\\pur'' imp'' -> (\\pur _ -> pur f) (\\h -> (\\pur' _ -> pur' x) (pur'' . h) imp'') imp'') by defn 269 | -- === FFC (\\pur'' imp'' -> (\\h -> (\\pur' -> pur' x) (pur'' . h) imp'') f) by beta 270 | -- === FFC (\\pur'' imp'' -> (\\pur' _ -> pur' x) (pur'' . f) imp'') by beta 271 | -- === FFC (\\pur'' imp'' -> (pur'' . f) x) by beta 272 | -- === FFC (\\pur'' _ -> pur'' (f x)) by defn-compose 273 | -- === pure (f x) by defn 274 | -- @ 275 | -- 276 | -- === Interchange 277 | -- 278 | -- @ 279 | -- u \<*\> pure y === pure (\\k -> k y) \<*\> u 280 | -- @ 281 | -- 282 | -- @ 283 | -- FFC ru \<*\> FFC (\\pur _ -> pur y) by defn 284 | -- === FFC (\\pur' imp' -> ru (\\u -> (\\pur _ -> pur y) (pur' . u) imp') imp') by defn 285 | -- === FFC (\\pur' imp' -> ru (\\u -> (pur' . u) y) imp') by beta 286 | -- === FFC (\\pur' imp' -> ru (\\u -> pur' (u y)) imp') by beta 287 | -- === FFC (\\pur' imp' -> ru (\\u -> pur' ((\\k -> k y) u)) imp') by beta 288 | -- === FFC (\\pur' imp' -> ru (\\u -> (pur' . (\\k -> k y)) u) imp') by defn-compose 289 | -- === FFC (\\pur' imp' -> ru (pur' . (\\k -> k y)) imp') by eta 290 | -- === FFC (\\pur' imp' -> (\\f -> ru (pur' . f) imp') (\\k -> k y)) by beta 291 | -- === FFC (\\pur' imp' -> (\\pur _ -> pur (\\k -> k y)) (\\f -> ru (pur' . f) imp') imp') by defn 292 | -- === FFC (\\pur _ -> pur (\\k -> k y)) \<*\> FFC ru 293 | -- @ 294 | -- 295 | -- === Composition 296 | -- 297 | -- @ 298 | -- pure compose \<*\> u \<*\> v \<*\> w === u \<*\> (v \<*\> w) 299 | -- @ 300 | -- 301 | -- Please send a Pull Request. (Proof seems straightforward, but tedious) 302 | -- 303 | -- 304 | -- == Monad Laws 305 | -- 306 | -- === Left Identity 307 | -- 308 | -- @ 309 | -- return a >>= f === f a 310 | -- @ 311 | -- 312 | -- @ 313 | -- FFC (\\pur' _ -> pur' a) >>= f 314 | -- === FFC (\\pur imp -> (\\pur' _ -> pur' a) (\\x -> unFFC (f x) pur imp) imp) by defn 315 | -- === FFC (\\pur imp -> (\\x -> unFFC (f x) pur imp) a) by beta 316 | -- === FFC (\\pur imp -> unFFC (f a) pur imp) by beta 317 | -- === FFC (unFFC (f a)) by eta 318 | -- === f a by eta 319 | -- @ 320 | -- 321 | -- 322 | -- === Right Identity 323 | -- 324 | -- @ 325 | -- (FFC mp) >>= return === (FFC mp) 326 | -- @ 327 | -- 328 | -- @ 329 | -- FFC mp >>= (\\x -> FFC (\\pur' _ -> pur' x)) by defn 330 | -- === FFC (\\pur imp -> mp (\\a -> unFFC ((\\x -> FFC (\\pur' _ -> pur' x)) a) pur imp) imp) by defn 331 | -- === FFC (\\pur imp -> mp (\\a -> unFFC (FFC (\\pur' _ -> pur' a)) pur imp) imp) by beta 332 | -- === FFC (\\pur imp -> mp (\\a -> pur a) imp) by beta 333 | -- === FFC (\\pur imp -> mp pur imp) by eta 334 | -- === FFC mp by eta 335 | -- @ 336 | -- 337 | -- 338 | -- === Associativity 339 | -- 340 | -- @ 341 | -- (FFC mp >>= f) >>= g === (FFC mp) >>= (\\x -> f x >>= g) 342 | -- @ 343 | -- 344 | -- @ 345 | -- FFC (\\pur imp -> unFFC (FFC mp >>= f) (\\a -> unFFC (g a) pur imp) imp) by defn (>>=) outer 346 | -- === FFC (\\pur imp -> unFFC (FFC (\\pur' imp' -> mp (\\b -> unFFC (f b) pur' imp') imp')) (\\a -> unFFC (g a) pur imp) imp) by defn (>>= inner) 347 | -- === FFC (\\pur imp -> mp (\\b -> unFFC (f b) (\\a -> unFFC (g a) pur imp)) imp) by beta 348 | -- === FFC (\\pur imp -> mp (\\b -> unFFC (FFC (\\pur' imp' -> unFFC (f b) (\\a -> unFFC (g a) pur' imp') imp')) pur imp) imp) by beta 349 | -- === FFC (\\pur imp -> mp (\\b -> unFFC (f b >>= g) pur imp) imp) by defn 350 | -- === FFC (\\pur imp -> mp (\\b -> unFFC ((\\z -> f z >>= g) b) pur imp) imp) by beta 351 | -- === FFC mp >>= (\\z -> f z >>= g) by defn 352 | -- @ 353 | --------------------------------------------------------------------------------