打印Haskell是一个纯函数吗?

bub*_*ubu 7 io monads haskell pure-function io-monad

在Haskell中打印是一个纯函数; 为什么或者为什么不?我认为这不是因为它并不总是返回与纯函数应该相同的值.

dan*_*iaz 8

类型的IO Int值不是真的Int.它更像是一张纸,上面写着"嘿Haskell运行时,请以Int这样的方式生成一个值".这张纸是惰性的并且保持不变,即使Int最终由运行时产生的s不同.

您可以通过将纸张分配给运行时将其发送到运行时main.如果IO动作永远不会妨碍main并且反而在某个容器内部萎缩,那么它将永远不会被执行.

返回IO动作的函数与其他函数一样纯粹.他们总是返回同一张纸.运行时对这些指令的作用是另一回事.

如果它们纯净,我们在改变之前必须要三思

foo :: (Int -> IO Int) -> IO Int
foo f = liftA2 (+) (f 0) (f 0)
Run Code Online (Sandbox Code Playgroud)

foo :: (Int -> IO Int) -> IO Int
foo f = let x = f 0 in liftA2 (+) x x
Run Code Online (Sandbox Code Playgroud)

  • @ user2407038至少在GHC中,`IO X`有[一种非常不同的表示](https://hackage.haskell.org/package/base-4.10.0.0/docs/src/GHC.Base.html#line-1197 )比'X`. (3认同)

Dam*_*ero 1

如果您刚刚阅读纯函数的标签(在给定相同参数值的情况下始终计算出相同结果值的函数,并且不会导致任何语义上可观察到的副作用或输出,例如可变对象或输出的突变) I/O 设备。)然后考虑打印类型:

\n\n
putStrLn :: String -> IO ()\n
Run Code Online (Sandbox Code Playgroud)\n\n

你会在那里发现一个技巧,它总是返回IO (),所以......,它会产生效果。所以就引用透明度而言不是纯粹的\n例如,getLine返回IO String但它也是一个纯函数。(@interjay 贡献),我想说的是,答案取决于问题:

\n\n

就值而言,相同的输入IO ()将始终具有相同的值。IO ()

\n\n

\n\n

就执行而言,它不是纯粹的,因为执行可能IO ()会产生副作用(在屏幕中放置一个字符串,在这种情况下看起来很无辜,但某些 IO 可能会发射核弹,然后返回 Int 42)

\n\n

您可以通过@Ben 的好方法更好地理解这里:

\n\n
\n

“有几种方法可以解释你如何“纯粹”操纵\n现实世界。一种说法是,IO 就像一个状态单子,只是\n所穿过的状态是你\n之外的整个世界\n n program;= (所以你的 Stuff -> IO DBThing 函数确实有一个额外的\n隐藏参数来接收世界,并且实际上返回一个\n DBThing以及另一个世界;它总是用不同的\n世界来调用,这就是为什么即使使用相同的东西调用时它也可以返回不同的 DBThing 值。另一种解释是 IO DBThing 值本身就是一个命令式程序;你的 Haskell 程序是完全纯函数,不执行任何操作IO,它返回一个执行 IO 的不纯程序,Haskell 运行时系统(不纯地)执行它返回的程序。”

\n
\n\n

还有@Erik Allik:

\n\n
\n

因此,返回 IO a 类型值的 Haskell 函数实际上不是在运行时执行的函数 \xe2\x80\x94,执行的是 IO a 值本身。所以这些函数实际上是纯函数,但它们的返回值代表非纯计算。

\n
\n\n

你可以在这里找到它们Understanding pure Functions in Haskell with IO

\n

  • @DamianLattenero 是的, `()` 是 `()` 类型的值,并且它是 `()` 类型的唯一值。但是 print 不会给你一个 `()` 类型的值,它给你一个 `IO ()` 类型的值,其中有很多(实际上是无限多个)不同的值,而 `()` 不是一个其中。例如, `print "hello"` 和 `print "world"` 生成的值是不同的 - 否则 `main = print "hello"` 和 `main = print "world"` 需要表现得与 `main 相同` 两者具有相同的值。 (4认同)
  • @DamianLattenero“IO () 本身就是一个值”不,不是。`IO ()` 类型有许多不同的值,甚至 `print` 也可以产生该类型的不同值(如果您传递不同的参数)。否则所有打印语句都会打印相同的内容。 (3认同)
  • 对于相同的输入,它总是返回相同的 IO 操作,但这与它返回 IO () 无关。例如,“getLine”返回“IO String”,但它也是一个纯函数。 (3认同)