有没有办法在纯函数中放置一些不纯的代码?

时间:2017-01-07 14:29:27

标签: haskell monads

IO就像Maybe一样,只是Monad的一个实例。另一方面,我们拥有MaybeJustNothing)的所有数据构造函数,但没有IO的构造函数。 ReaderWriter也不导出构造函数,它们具有函数,它返回此类型的实例(readerwriter),更重要的是runReader和{ {1}},从Monad解包计算结果。

有没有办法解开IO Monad?我想拥有纯粹的功能,它可以在引擎盖下进行一些不纯的IO计算。目前我能够与大多数Monads一起做到这一点

我知道这种棘手功能的一个例子:runWriter

3 个答案:

答案 0 :(得分:2)

unsafePerformIO :: IO a -> a(基数)中的

System.IO.Unsafe

请谨慎使用,并仔细阅读documentation中的说明。

答案 1 :(得分:1)

是否可以在纯函数中放置一些不纯代码?

  • 如果种方法可以怎么办?

  • 所有人可以使用它怎么办?

您愿意坐下来仔细检查 用于检查它们是否安全的每个库和程序 的来源吗?

如果您愿意,那么Haskell可能不适合您-我建议您看看Standard MLOCaml等语言。


您还在这里吗?

那么,您可以使用另一种方法:从不纯代码中提取纯函数。之所以可以这样做是因为 函数是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来实现它是有意义的。数组更新具有与命令式语言相同的性能。