如何使用免费monads实现Reader?

好的,我已经想出了如何使用operational包来实现Reader (和ReaderT ,未显示):

{-# LANGUAGE GADTs, ScopedTypeVariables #-}

import Control.Monad.Operational

data ReaderI r a where
    Ask :: ReaderI r r

type Reader r a = Program (ReaderI r) a

ask :: Reader r r
ask = singleton Ask

runReader :: forall r a. Reader r a -> r -> a
runReader = interpretWithMonad evalI
    where evalI :: forall b. ReaderI r b -> (r -> b)
          evalI Ask = id

但我无法想象自己的生活如何与免费的monads(我使用Edward Kmett的free套餐)做到这一点。 我得到的最接近的是这个,我知道这是欺骗(关于((->) r)已经是单子的事情):

import Control.Monad.Free

type Reader r a = Free ((->) r) a

ask :: Reader r r
ask = Free Pure

runReader :: Reader r a -> r -> a
runReader (Pure a) _ = a
runReader (Free k) r = runReader (k r) r

-- Or, more simply and tellingly:
--
-- > runReader = retract

即使这并不像我想象的那样愚蠢,这不是我想要的,因为我想要的基本上是能够将Reader作为数据进行检查......


除了他们的方式,我不认为这是可以做到的。 但是,我不认为这对读者来说是独一无二的。 考虑免费的monad版本的作家

data WriterF m a = WriterF m a deriving (Functor)

type Writer m = Free (WriterF m)

显然, WriterF与作者是同构的,但这确实表现出我们期望的简单代数的方式

algebraWriter :: Monoid m => WriterF m (m,a) -> (m,a)
algebraWriter (WriterF m1 (m2,a)) = (m1 <> m2,a)

从而

runWriter :: Monoid m => Writer m a -> (m,a)
runWriter (Pure a) = (mempty,a)
runWriter (Free x) = algebraWriter . fmap runWriter $ x

同样,我认为免费阅读器为

type ReaderF r = (->) r

type Reader r = Free (ReaderF r)

我喜欢这个,因为添加它们会给你状态monad

type State x = Free ((ReaderF x) :+: (WriterF x))

runState :: State x a -> x -> (a,x)
runState (Pure a) x                    = (a,x)
runState (Free (Inl f)) x              = runState (f x) x
runState (Free (Inr (WriterF x f))) _  = runState f x

请注意,您的操作解决方案可以通过使用“自由仿函件”与Free使用,正如任何可与操作一起使用的方法一样

data FreeFunctor f x = forall a. FreeFunctor (f a) (a -> x)

但是, FreeFunctor ReaderI也同构于(->)


那么,我现在已经看了3个小时了,我想我找到了我更喜欢的东西。 由于Reader应用程序与Reader monad相同,因此我们可以尝试使用适用的operational版本:

{-# LANGUAGE RankNTypes, GADTs, FlexibleInstances #-}

import Control.Applicative

data ProgramA instr a where
    Pure  :: a -> ProgramA r a
    Ap    :: ProgramA r (a -> b) -> ProgramA r a -> ProgramA r b
    Instr :: instr a -> ProgramA instr a

infixl `Ap`

instance Functor (ProgramA instr) where
    fmap f (Pure a) = Pure (f a)
    fmap f (ff `Ap` fa) = ((f .) <$> ff) `Ap` fa
    fmap f instr = Pure f `Ap` instr

instance Applicative (ProgramA instr) where
    pure = Pure
    (<*>) = Ap

interpretA :: Applicative f =>
              (forall a. instr a -> f a)
           -> ProgramA instr a
           -> f a
interpretA evalI (Pure a) = pure a
interpretA evalI (ff `Ap` fa) = interpretA evalI ff <*> interpretA evalI fa
interpretA evalI (Instr i) = evalI i

data ReaderI r a where
    Ask :: ReaderI r r

type Reader r a = ProgramA (ReaderI r) a

ask :: Reader r r
ask = Instr Ask

runReader :: Reader r a -> r -> a
runReader = interpretA (Ask -> id)

instance Monad (ProgramA (ReaderI r)) where
    return = pure
    ma >>= f = runReader <$> fmap f ma <*> ask

ProgramA (ReaderI r) a)可以比Program (ReaderI r) aFree ((->) r) a更直接地进行检查Free ((->) r) a

链接地址: http://www.djcxy.com/p/70087.html

上一篇: How do I implement Reader using free monads?

下一篇: VS 2012 Automatically updating IIS path on launch