Lui*_*las 8 monads haskell free-monad
好的,所以我已经想出如何使用包来实现Reader
(并且ReaderT
未显示)operational
:
{-# 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
Run Code Online (Sandbox Code Playgroud)
但我无法弄清楚如何使用免费monad(我使用Edward Kmett的free
包)来解决这个问题.我得到的最接近的是这个,我明白是作弊(关于如何((->) r)
已经是monad):
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
Run Code Online (Sandbox Code Playgroud)
即使这不像我怀疑的那样愚蠢,但这不是我想要的,因为我想要的,基本上就是能够检查Reader
数据......
我认为除了你的方式之外这是不可能的。但是,我不认为这对读者来说是独一无二的。考虑 writer 的免费 monad 版本
data WriterF m a = WriterF m a deriving (Functor)
type Writer m = Free (WriterF m)
Run Code Online (Sandbox Code Playgroud)
显然,WriterF
与 writer 同构,但这确实符合我们对简单代数的期望
algebraWriter :: Monoid m => WriterF m (m,a) -> (m,a)
algebraWriter (WriterF m1 (m2,a)) = (m1 <> m2,a)
Run Code Online (Sandbox Code Playgroud)
因此
runWriter :: Monoid m => Writer m a -> (m,a)
runWriter (Pure a) = (mempty,a)
runWriter (Free x) = algebraWriter . fmap runWriter $ x
Run Code Online (Sandbox Code Playgroud)
同样,我认为免费阅读器是
type ReaderF r = (->) r
type Reader r = Free (ReaderF r)
Run Code Online (Sandbox Code Playgroud)
我喜欢这个,因为添加它们会给你状态单子
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
Run Code Online (Sandbox Code Playgroud)
Free
请注意,您的操作解决方案可以通过使用“自由函子”来使用,任何与操作一起使用的解决方案都可以使用
data FreeFunctor f x = forall a. FreeFunctor (f a) (a -> x)
Run Code Online (Sandbox Code Playgroud)
但是,这FreeFunctor ReaderI
也同构于(->)
.