Sau*_*nda 3 monads haskell monad-transformers
我正在尝试创建一个只允许特定IO功能的monad.这意味着这个假设的monad不能是a MonadIO并且不能被允许liftIO被调用.
这是我到现在所拥有的,但我坚持使用以下Monad实例AppM:
data AppM a = AppM {unwrapAppM :: ReaderT Env (LoggingT IO) a}
instance Functor AppM where
fmap fn appm = AppM $ fmap fn (unwrapAppM appm)
instance Applicative AppM where
pure a = AppM $ pure a
Run Code Online (Sandbox Code Playgroud)
如果你只是想隐藏MonadIO你的性能AppM
我会继续并投入
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
Run Code Online (Sandbox Code Playgroud)
并将data声明更改为
newtype App a = App {runApp :: ReaderT Env (LoggingT IO) a}
deriving (Functor, Applicative, Monad, MonadReader Env,
, MonadLoggerIO }
Run Code Online (Sandbox Code Playgroud)
因此,如果您需要喜欢可以提供图书馆内部内容的操作,那么您App就不是MonadIOliftIO
putStrLn :: String -> App ()
putStrLn = fmap App . liftIO Prelude.putStrLn
Run Code Online (Sandbox Code Playgroud)
注:liftIO对于IS ReaderT Env (LoggingT IO) (),然后包装到App了,你不要暴露充分IO能力.
至于问题如何落实Functor,Applicative而Monad它仅仅是包装/解包的单纯任务:
instance Functor App where
fmap f = App . fmap f . runApp
instance Applicative App where
pure = App . pure
mf <*> mx = App (runApp mf <*> runApp mx)
instance Monad App where
mx >>= f = App $ (runApp mx) >>= (runApp . f)
Run Code Online (Sandbox Code Playgroud)
最后一行是唯一棘手的 - 作为
>>= :: ReaderT Env (LoggingT IO) a -> (a -> ReaderT Env (LoggingT IO) b) -> ReaderT Env (LoggingT IO) b
Run Code Online (Sandbox Code Playgroud)
但mx :: App a和f :: a -> App b所以我们需要
runApp :: App a -> ReaderT Env (LoggingT IO) a
Run Code Online (Sandbox Code Playgroud)
打开结果类型f以在打开的设置中工作 - 这在写下来时似乎非常明显,但在此之前可能会引起一些麻烦.
我发现那篇论文有人把我和很长时间联系起来(但在同一个星系中)来自monad读者Ed Z. Yang - Three Monads(逻辑,提示,失败)