haskell - 负位置的 IO 动作会产生意想不到的结果吗?
问题描述
Monad IO
关于和之间的区别似乎有一些无证知识IO
。此处和此处的备注) 提示IO a
可用于否定位置,但可能会产生意想不到的后果:
引用 Snoyman 1:
但是,我们知道一些控制流(例如异常处理)没有被使用,因为它们与 MonadIO 不兼容。(原因:MonadIO 要求 IO 处于正位置,而不是负位置。)这让我们知道,例如, foo 在 ContT 或 Conduit 等基于延续的 monad 中使用是安全的。
和Kmett 2:
我倾向于导出具有 MonadIO 约束的函数......只要它不必在负位置(作为参数)采取类似 IO 的动作。
当我的代码确实必须将另一个单子动作作为参数时,我通常不得不停下来考虑一下。
程序员应该知道的这些功能是否存在危险?
例如,这是否意味着运行任意基于延续的操作可能会重新定义控制流,从而以Monad IO
基于接口安全的方式给出意想不到的结果?
解决方案
程序员应该知道的这些功能是否存在危险?
没有危险。恰恰相反,Snoyman 和 Kmett 的观点是,Monad IO
不要让你IO
以消极的积极态度度过难关。
假设你想概括putStrLn :: String -> IO ()
. 你可以,因为IO
它处于积极的位置:
putStrLn' :: MonadIO m => String -> m ()
putStrLn' str = liftIO (putStrLn str)
现在,假设您想概括handle :: Exception e => (e -> IO a) -> IO a -> IO a
. 你不能(至少不能用 just MonadIO
):
handle' :: (MonadIO m, Exception e) => (e -> m a) -> m a -> m a
handle' handler act = liftIO (handle (handler . unliftIO) (unliftIO act))
unliftIO :: MonadIO m => m a -> IO a
unliftIO = error "MonadIO isn't powerful enough to make this implementable!"
你需要更多的东西。如果您对如何做到这一点感到好奇,请查看lifted-base
. 例如:handle :: (MonadBaseControl IO m, Exception e) => (e -> m a) -> m a -> m a
。
推荐阅读
- maximo - 移动应用程序的下载按钮
- c - 为什么这些类型定义得到相同的结果
- python - 重新输入重定向 URL 时获取 'spotipy.oauth2.SpotifyOauthError: Bad Request'
- java - 带 8 位数字的模幂运算
- django - 如何知道哪个用户添加了另一个用户?
- python - 如何阻止在python中键入按键
- appium - org.openqa.selenium.NoSuchSessionException:会话终止或未启动
- python - 使用不同线程连接不同数据库后是否关闭部分连接会影响其他线程
- c# - Unity中的基本比较和分配问题
- android - OpenGLES基于触摸绘制箭头