Fir*_*tul 7 haskell functional-programming lazy-evaluation
假设你在haskell中有一个nullary函数,它在代码中多次使用.它总是只评估一次吗?我已经测试了以下代码:
sayHello :: Int
sayHello = unsafePerformIO $ do
putStr "Hello"
return 42
test :: Int -> [Int]
test 0 = []
test n = (sayHello:(test (n-1)))
Run Code Online (Sandbox Code Playgroud)
当我调用测试10时,它会将"Hello"写入一次,因此它表示在第一次评估后存储了函数的结果.我的问题是,它有保证吗?我会在不同的编译器中得到相同的结果吗?
编辑 我使用unsafePerformIO的原因是检查sayHello是否被多次评估.我不在我的程序中使用它.通常我希望sayHello每次评估都会得到完全相同的结果.但这是一个耗时的操作,所以我想知道它是否可以通过这种方式访问,或者是否应该作为参数传递,以确保它不被多次评估,即:
test _ 0 = []
test s n = (s:(test (n-1)))
...
test sayHello 10
Run Code Online (Sandbox Code Playgroud)
根据答案,应该使用它.
sha*_*haf 17
没有诸如Nullary函数之类的东西.Haskell中的函数只有一个参数,并且始终具有类型... -> ....sayHello是一个价值 - Int而不是一个功能.有关更多信息,请参阅此文
保证:不,你没有得到任何保证.Haskell报告指出Haskell是非严格的 - 所以你知道最终会减少什么价值 - 但不是任何特定的评估策略.GHC通常使用的评估策略是惰性评估,即通过共享进行非严格评估,但它没有对此做出强有力的保证 - 优化器可以对您的代码进行洗牌,以便对事物进行多次评估.
还有各种例外 - 例如,foo :: Num a => a是多态的,因此它可能不会被共享(它被编译为实际的函数).有时,纯值可能会被多个线程同时评估(在这种情况下不会发生,因为unsafePerformIO明确地使用noDuplicate它来避免它).因此,当你编程时,你通常可以期待懒惰,但如果你想要任何形式的保证,你必须非常小心.报告本身不会真正给你任何东西如何你的程序进行评估.
unsafePerformIO当然,为您提供更少的担保方式.有一个原因,它被称为"不安全".
顶级无参数函数sayHello称为常量应用形式,并且总是被记忆(至少在GHC中 - 参见http://www.haskell.org/ghc/docs/7.2.1/html/users_guide/profiling.html).你不得不求助于传递虚假参数和关闭优化以不在全球共享CAF的技巧.
编辑:从上面的链接引用 -
Haskell是一种惰性语言,某些表达式只被评估过一次.例如,如果我们写:
x = nfib 25那么x只会被评估一次(如果有的话),随后的需求x会立即看到缓存的结果.该定义x称为CAF(Constant Applicative Form),因为它没有参数.