在Haskell中打印是一个纯函数;为什么或者为什么不?我认为这不是因为它并不总是返回与纯函数相同的值。
答案 0 :(得分:5)
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
答案 1 :(得分:2)
如果您只是读取纯函数的标签(一个函数,它总是在给定相同参数值的情况下评估相同的结果值,并且不会导致任何语义上可观察到的副作用或输出,例如mutable变异对象或输出到I / O设备。)然后在打印类型中思考:
putStrLn :: String -> IO ()
你会在那里找到一个技巧,它总是返回IO ()
,所以... 否 ,它会产生效果。所以在Referential Transparency方面并不纯粹
例如,getLine
返回IO String
,但它也是纯函数。 (@interjay贡献),我想说的是,答案非常接近这个问题:
就价值问题而言,相同输入的IO ()
值始终为IO ()
。
和
关于执行问题,它不是纯粹的,因为执行它
IO ()
可能有副作用(在屏幕上放一个字符串,在此
案件看起来如此无辜,但有些IO可以吃核弹,而且
然后返回Int 42)
你可以通过@Ben的好方法更好地理解:
“有几种方法可以解释你是如何”纯粹“操纵的 现实中。一个是说IO只是一个状态monad 被穿越的国家是你外面的整个世界 program; =(所以你的Stuff - > IO DBThing函数确实有额外的功能 隐藏的论据,接收世界,并实际返回一个 DBThing与另一个世界;它总是被称为不同的 世界,这就是为什么它甚至可以返回不同的DBThing值 当用相同的东西调用时)。另一种解释是IO DBThing值本身就是一个必要的程序;你的Haskell程序是 一个完全没有IO的完全纯函数,它返回一个不纯的程序 做IO,Haskell运行时系统(不纯)执行 程序它返回。“
和@Erik Allik:
找到它们因此,返回类型IO a的值的Haskell函数实际上不是 在运行时执行的函数 - 执行的内容 IO是一个值本身。所以这些功能实际上是纯粹的 它们的返回值代表非纯计算。
答案 2 :(得分:0)
是的,print
是一个纯函数。它返回的值为IO ()
类型,您可以将其视为输出传入的字符串的一堆代码。对于传入的每个字符串,它总是返回相同的代码。