Haskell中的print
是纯函数吗;为什么?我认为它不是,因为它并不总是返回与纯函数应该返回的值相同的值。
类型为IO Int
的值实际上不是Int
。它更像是一张纸,上面写着"嘿,Haskell运行时,请以这样那样的方式生成Int
值"。这张纸是惰性的,并且保持不变,即使运行时最终生成的Int
是不同的。
通过将纸张分配给main
,可以将其发送到运行时。如果IO
操作从未妨碍main
,而是在某个容器中搁置,那么它将永远不会被执行。
返回IO
操作的函数与其他函数一样纯粹。他们总是归还同一张纸。运行时如何处理这些指令是另一回事。
如果它们不是纯的,我们在更改之前必须三思而后行
foo :: (Int -> IO Int) -> IO Int
foo f = liftA2 (+) (f 0) (f 0)
至:
foo :: (Int -> IO Int) -> IO Int
foo f = let x = f 0 in liftA2 (+) x x
print
是一个纯函数。它返回的值的类型为IO ()
,您可以将其视为输出传入字符串的一组代码。对于传入的每个字符串,它总是返回相同的代码。
如果您刚刚阅读纯函数的标记(一个函数,在给定相同的参数值的情况下,它总是计算为相同的结果值,并且不会导致任何语义上可观察到的副作用或输出,例如可变对象的突变或I/O设备的输出。)然后在打印类型中思考:
putStrLn :: String -> IO ()
你会在那里找到一个技巧,它总是返回IO ()
,所以…否,它会产生效果。因此,就参考透明度而言,它并不纯粹例如,getLine
返回IO String
,但它也是一个纯函数。(@interjay贡献),我想说的是,答案非常接近这个问题:
就值而言,对于相同的输入,IO ()
将始终是相同的IO ()
值
和
在执行问题上,它不是纯粹的,因为执行IO ()
可能有副作用(在屏幕上放一个字符串这个案子看起来很无辜,但一些IO可能会吃到核弹然后返回Int 42)
你可以更好地理解@Ben在这里的好方法:
"有几种方法可以解释你是如何"纯粹"操纵的现实世界。一种是说IO就像一个状态monad,只是正在经历的状态是你之外的整个世界程序;=(所以你的Stuff->IO DBThing函数真的有一个额外的接收世界并实际返回DBThing与另一个世界;它总是用不同的名字来称呼世界,这就是为什么它甚至可以返回不同的DBThing值当用相同的Stuff调用时)。另一种解释是IODBThing的价值本身就是一个命令程序;你的Haskell程序一个完全纯的函数,不执行IO,返回一个不纯的程序执行IO,并且Haskell运行时系统(impuly)执行程序返回。">
和@Erik Allik:
因此,返回IO a类型值的Haskell函数实际上不是在运行时执行的函数——执行了什么IO本身就是一个值。所以这些函数实际上是纯的,但是它们的返回值表示非纯计算。
你可以在这里找到它们了解Haskell中的纯函数和IO