multiply :: Int -> Int -> Int
multiply a b = a * b
minus :: Int -> Int -> Int
minus a b = a - b
minus2 :: Int -> Int -> Int
minus2 a b = b – a
minus2 (multiply (minus 3 5) 7) 9
minus2 ((minus 3 5) * 7) 9
9 - ((minus 3 5) * 7)
9 - ((3 - 5) * 7)
9 - ((-2) * 7)
9 - (-14)
23
运行minus2 (multiply (minus 3 5) 7) 9
行
我有Haskell使用的正确评估顺序吗?
函数式编程还是一个新事物,所以我不确定我的“惰性评估”过程是否正确。
答案 0 :(得分:3)
您可以通过用(error "x")
,(error "y")
等替换子表达式来检验您的假设。首先评估哪个错误是运行表达式时出现的错误。
答案 1 :(得分:0)
至此,评估可以以编译器希望的任何顺序进行,只要它能得到正确的答案即可。例如,它可以将整个表达式优化为23,并且在运行时完全不求值。除减法外,它可以在算术运算符的右边先于左边。它可以在运行时随机决定先评估哪个。
忽略这一点,有关如何手动完成工作的解释,请参见"How Lazy Evaluation Works in Haskell"。
但是,如何手动找出答案并不是此答案的重点。您的问题是Haskell实际使用的评估顺序是什么,因此该答案大体上是要告诉您使用您选择的编译器进行编译时程序使用的评估顺序(忽略一些对于评估顺序的基本理解无关紧要的警告)。
通过一些工作,我们可以让Haskell告诉我们它评估的顺序。如果您在学校里,您可能想学习如何在没有帮助的情况下手动查找评估顺序,以便在测试中表现出色。
建议您仅执行此操作以检查您对答案有把握的答案。如果遇到困难,也可以使用它,但是您应该只阅读直到遇到困难为止,才能查看下一步是下一步,以便对为什么作一个有根据的猜测,以便您可以通过实验开始了解规则。结合以上链接的文章,这将有很大帮助。
为此,我们可以使用Debug.Trace
的函数代替error
来扩展JonasDuregård的答案。 Debug.Trace
的函数可以在 开始或停止评估时输出结果,因此在这里很合适:
import Debug.Trace
-- Show result
r :: String -> Int -> Int
r nm n = trace ("Result of " ++ nm ++ " is " ++ show n) n
-- Show evaluation of Int -> Int -> Int function
f :: String -> (Int -> Int -> Int) -> Int -> Int -> Int
f nm g a b = e nm $ g a b
-- Show evaluation of an Int
e :: String -> Int -> Int
e nm = r nm . trace ("Evaluating " ++ nm)
-- Show Int literal
i :: Int -> Int
i n = e (show n) n
multiply :: Int -> Int -> Int
multiply a b = e "multiply" $ (f "multiply's *" (*))
(e "multiply's a" a)
(e "multiply's b" b)
minus :: Int -> Int -> Int
minus a b = e "minus" $ (f "minus's -" (-))
(e "minus's a" a)
(e "minus's b" b)
minus2 :: Int -> Int -> Int
minus2 a b = e "minus2" $ (f "minus2's -" (-))
(e "minus2's b" b)
(e "minus2's a" a)
main :: IO ()
main = print $ minus2 (multiply (minus (i 3) (i 5)) (i 7)) (i 9)
在纸上解决问题后,您可以使用the results of the above code run on GHC查看答案。它告诉您使用GHC编译时代码使用什么评估顺序。
您也可以通过您选择的Haskell编译器运行此程序。