Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 如何创建允许IO但不是MonadIO的monad?_Haskell_Monads_Monad Transformers - Fatal编程技术网

Haskell 如何创建允许IO但不是MonadIO的monad?

Haskell 如何创建允许IO但不是MonadIO的monad?,haskell,monads,monad-transformers,Haskell,Monads,Monad Transformers,我试图创建一个只允许特定IO函数的monad。这意味着这个假设的monad不能是MonadIO,也不能允许调用liftIO 这是我到目前为止所拥有的,但我一直使用AppM的Monad实例: data AppM a = AppM {unwrapAppM :: ReaderT Env (LoggingT IO) a} instance Functor AppM where fmap fn appm = AppM $ fmap fn (unwrapAppM appm) instance Ap

我试图创建一个只允许特定IO函数的monad。这意味着这个假设的monad不能是
MonadIO
,也不能允许调用
liftIO

这是我到目前为止所拥有的,但我一直使用
AppM的
Monad
实例:

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

如果您只是想隐藏
AppM的
MonadIO
-ness

我会继续写一篇文章

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
并将
数据
声明更改为

newtype App a = App {runApp :: ReaderT Env (LoggingT IO) a}
              deriving (Functor, Applicative, Monad, MonadReader Env,
                       , MonadLoggerIO }
因此,你的
App
不是
MonadIO
,如果你需要
liftIO
类似的动作,你可以在你的库中提供类似的动作

putStrLn :: String -> App ()
putStrLn = fmap App . liftIO Prelude.putStrLn
注意:
liftIO
用于
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)
但是
mx::App a
f::a->App b
所以我们需要

runApp :: App a -> ReaderT Env (LoggingT IO) a
打开
f
的结果类型以在“打开”设置中工作-这在写下时似乎非常明显,但在此之前可能会引起一些头痛

更新2
我发现有人把我和monad reader联系了很长一段时间(但在同一个银河系中)

我已经有一段时间没有问过类似的问题了,所以我不是100%确定,但有人建议看一下。你可以将IO动作定义为GADT,并像解释器一样执行它们,因此,将io限制在您想要的范围内,您可以使用
Free
执行此操作。另一种选择是使用
mtl
风格的api。你想到了哪些特定的函数?更大的想法是——使用类型类约束只允许特定的IO功能,这样一个函数的签名会立即告诉读者它在做什么类型的IO。太棒了。但是,就我的理解而言,Monad实例的代码在本例中是什么样子的?@SaurabhNanda-updated-这就是您要寻找的吗?是的。似乎是我需要的。让我在笔记本电脑上试一下,然后再回来找你。也许这是非常明显的(但为了将来可能不知道的读者的利益)-为了以这种方式隐藏
App
IO
,必须不导出
App
构造函数(即
App
必须是抽象类型);而且您必须(在GHC的最新版本上)向
应用程序
数据添加角色注释。强制。强制
允许在构造函数未导出时提取内部表示。
runApp :: App a -> ReaderT Env (LoggingT IO) a