给出Haskell 值(根据Rein Heinrich的评论编辑)f:
f :: IO Int
f = ... -- ignoring its implementation
Run Code Online (Sandbox Code Playgroud)
引用"Idris的类型驱动开发"
纯函数的关键属性是相同的输入总是产生相同的结果.此属性称为参照透明度
是f,和,即IO ...Haskell中的所有函数,纯粹?在我看来,从那以后,它们lookInDatabase :: IO DBThing不会总是返回相同的值,因为:
return MyDbThing导致结果总之,是f(和IO ...一般的功能)纯粹?如果是,那么请纠正我的错误理解,因为我试图f用我的t=...例子反驳功能纯度.
从概念上讲,IO实际上是一种单独的语言.它是Haskell RTS(运行时系统)的语言.它在Haskell中实现为(相对简单的)嵌入式DSL,其"脚本"具有该类型IO a.
因此返回类型值的Haskell函数IO a实际上不是在运行时执行的函数 - 执行的是IO a值本身.所以这些函数实际上是纯粹的,但它们的返回值代表非纯计算.
从语言设计的角度来看,IO是一个非常优雅的黑客,可以将非纯粹的丑陋完全隔离开,同时将其紧密地融入其纯净的环境中,而不需要使用特殊的外壳.换句话说,该设计并不能解决由不纯IO引起的问题,但它至少不会影响代码的纯部分.
下一步是研究FRP - 使用FRP,您可以使包含IO的层更薄,并将更多非纯逻辑移动到纯逻辑中.
您可能还想阅读John Backus关于函数编程主题的着作,Von Neumann架构的局限性等.如果您对纯度和IO之间的关系感兴趣,Conal Elliott也是谷歌的名字.
PS也值得注意的是,虽然IO严重依赖monad来解决懒惰评估的问题,并且因为monad是构建嵌入式DSL的一种非常好的方式(其中IO只是一个例子),monad更加通用比IO,所以尽量不要在相同的上下文中考虑IO和monad - 它们是两个独立的东西,两者都可以存在而没有另一个.
首先,您注意到 I/O 操作不是纯粹的,这是正确的。这不可能。但是,所有函数的纯度是 Haskell 的一大亮点,那么到底发生了什么?
无论您是否喜欢,应用到具有IO Something某些参数的a (也可能被错误地称为“返回 a”)的函数将始终返回IO Something具有相同参数的相同值。monadIO允许您将操作“隐藏”在 monad 所充当的容器内。当你有一个 时IO String,该函数/对象不包含/ String,[Char]而是一种承诺,即你String将来会以某种方式得到它。因此,IO包含需要执行不纯 I/O 操作时要执行的操作的信息。
毕竟,IO执行操作的唯一方法是具有名称main,或者成为其依赖项main。由于 monad 的灵活性,您可以“连接”IO操作。像这样的程序...(注意:这段代码不是一个好主意)
main = do
input <- getLine
putStrLn input
Run Code Online (Sandbox Code Playgroud)
合成糖是...
main =
getLine >>= (\input -> putStrLn input)
Run Code Online (Sandbox Code Playgroud)
这表明mainI/O 操作是通过将从标准输入读取的字符串打印到标准输出(后跟换行符)而产生的。你看到魔法了吗?IO只是一个包装器,表示在不纯的上下文中要做什么,以产生一些给定的输出,但不是该操作的结果,因为这需要 Haskell 语言承认不纯的代码。
把它想象成一种收据。如果你有一个蛋糕的收据(阅读:IOmonad)(阅读:Somethingin IO Something),你知道如何制作蛋糕,但你无法制作蛋糕(因为你可以搞砸那个杰作)。相反,Master Chief(读:Haskell 运行时系统的最基本部分,负责应用main)为你做肮脏的工作(读:做不纯/非法的事情),而且,最重要的是,他不会犯任何错误(阅读:破坏代码纯度)......当然除非烤箱坏了(阅读:)System.IO.Error,但他知道如何清理它(阅读:代码将永远保持纯净)。
IO这是不透明类型的原因之一。它的实现有些争议(直到您阅读 GHC 的源代码),并且最好保留为实现定义的。
只要快乐就好,因为你已经被纯洁照亮了。很多程序员甚至不知道 Haskell 的存在!
我希望这对你有所启发!