IO
就像Maybe
一样,只是Monad
的一个实例。另一方面,我们拥有Maybe
(Just
和Nothing
)的所有数据构造函数,但没有IO
的构造函数。 Reader
和Writer
也不导出构造函数,它们具有函数,它返回此类型的实例(reader
和writer
),更重要的是runReader
和{ {1}},从Monad解包计算结果。
有没有办法解开IO Monad?我想拥有纯粹的功能,它可以在引擎盖下进行一些不纯的IO计算。目前我能够与大多数Monads一起做到这一点
我知道这种棘手功能的一个例子:runWriter
答案 0 :(得分:2)
答案 1 :(得分:1)
是否可以在纯函数中放置一些不纯代码?
如果有种方法可以怎么办?
所有人可以使用它怎么办?
您愿意坐下来仔细检查 用于检查它们是否安全的每个库和程序 的来源吗?
如果您愿意,那么Haskell可能不适合您-我建议您看看Standard ML或OCaml等语言。
您还在这里吗?
那么,您可以使用另一种方法:从不纯代码中提取纯函数。之所以可以这样做是因为 函数是Haskell中的一等值-特别是,函数可用作参数,例如:
fmap :: Functor f => (a -> b) -> f a -> f b
liftM2 :: Monad m => (a -> b -> c) -> m a -> m b -> m c
随着抽象能力的提高,您将越来越多的工作委托给纯代码(以函数的形式),而只有一小部分定义受效果(包括main :: IO ()
)的污染。首先需要付出额外的努力,但长期的回报是可观的……
答案 2 :(得分:0)
正确的答案是
好吧,是,GHC有一个名为unsafePerformIO
的东西,但这是不是 Haskell标准的一部分,只是一个允许的hack使用外部函数接口调用来自其他语言的某些“道德纯粹”函数,并且如果您在纯Haskell中直接编写它们,则会反映这些函数的类型。
请注意,“展开IO
monad”不只会为您提供该计算的结果。如果IO
是一个公共构造函数类型,它实际上看起来(概念上)类似于以下内容:
data IO' a =
WriteToFile FilePath String
| PutStr String
| WithStdLine (String -> IO' a)
| ...
| SequenceIO (IO' ()) (IO' a)
对这样的IO' a
值进行模式匹配通常不会让您访问a
类型的任何内容,它只会为您提供一些描述要执行的操作,也许某些函数可能从从环境中获得的中间结果中产生a
值。
实际完成有用工作的唯一方法就是现在仍然如此:通过将其绑定到类似main
动作的东西,然后由某个“真实世界实体”(运行时)执行。
如果你想实现一个描述正确的数学(即纯粹)函数的算法,但似乎适用于具有变异等的命令式编程风格,那么你不应该在IO
monad中实现它。所有。您可能只需选择合适的数据结构就可以在普通的纯Haskell98中实现它,或者使用the ST
monad来实现它是有意义的。数组更新具有与命令式语言相同的性能。