假设你在 haskell 中有一个 nullary 函数,它在代码中被多次使用。它总是只评估一次吗?我已经测试了以下代码:
sayHello :: Int
sayHello = unsafePerformIO $ do
putStr "Hello"
return 42
test :: Int -> [Int]
test 0 = []
test n = (sayHello:(test (n-1)))
当我调用测试 10 时,它只写一次“Hello”,所以它表示函数的结果在第一次评估后存储。我的问题是,有保障吗?我会在不同的编译器中得到相同的结果吗?
编辑
我使用 unsafePerformIO 的原因是检查 sayHello 是否被多次评估。我不在我的程序中使用它。通常我希望 sayHello 每次评估时都有完全相同的结果。但这是一个耗时的操作,所以我想知道是否可以通过这种方式访问它,或者是否应该将它作为参数传递到需要确保它不会被多次评估的地方,即:
test _ 0 = []
test s n = (s:(test (n-1)))
...
test sayHello 10
根据答案,应该使用它。
最佳答案
没有零函数之类的东西。 Haskell 中的函数只有一个参数,并且总是类型为 ... -> ...
. sayHello
是一个值——Int
-- 但不是函数。见 this article更多。
关于保证:不,你并没有真正得到任何保证。 Haskell 报告指出 Haskell 是非严格的——所以你知道事情最终会降低到什么值(value)——但不是任何特定的评估策略。 GHC一般采用的评价策略是lazy evaluation ,即非严格的共享评估,但它并没有对此做出强有力的保证——优化器可以对你的代码进行洗牌,以便对事物进行多次评估。
还有各种异常(exception)——例如,foo :: Num a => a
是多态的,所以它可能不会被共享(它被编译成一个实际的函数)。有时一个纯值可能同时被多个线程计算(在这种情况下不会发生,因为 unsafePerformIO
明确使用 noDuplicate
来避免它)。因此,当您编程时,通常会出现懒惰,但如果您想要任何形式的保证,则必须非常小心。报告本身不会真正为您提供有关如何评估您的程序的任何信息。unsafePerformIO
当然,给你的保证更少。它被称为“不安全”是有原因的。
关于haskell - 在 Haskell 中评估零函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17078607/