为什么haskell seq函数为WHNF做出第一个参数?

时间:2016-09-17 07:25:36

标签: haskell seq

我认为seq很难理解,因为它首先向WHNF提出了论据。

如果seq将第一个参数设置为普通形式,则很容易理解。

使用WHNF而不是NF有什么好处?

为什么haskell委员会选择在seq函数中使用WHNF?

1 个答案:

答案 0 :(得分:1)

首先,Haskell的API在WHNF和NF之间没有偏好:它同时提供seqdeepseq

所以也许你的问题是为什么WHNF存在?简而言之,这是最不可能的评估。完整的计算将是这样的:

  1. 未评价(thunk)
  2. WHNF:最知名的构造函数
  3. 更深入的评估
  4. NF:值完全计算
  5. 但是,Haskell很懒,它试图尽可能少地计算以获得最终结果。例如,要计算列表l的长度,Haskell必须知道l[]还是_ : t。然后递归地回答关于t的相同问题。因此,在最终构造函数:之前只需要构造函数[]的数量。根据定义,这是连续的WHNF,它只提取值的最外部构造函数。

    最外面的构造函数是您必须知道的关于实际对其执行某些操作的值的最小信息,例如在case of中选择分支,就像在上面的length中一样。这是WHNF对NF的兴趣。

    请注意,对于像Int这样的简单类型,每个值都是自己的构造函数(2-715,...),因此WHNF = NF它们。

    最后,您很少关心所有这些:编译器的工作是尽快执行您的程序。在foldl (+) 0 [1..100]的评估中,如果您试图找出列表[1..100]何时在NF中完成,那么您将完全错误。编译器将该折叠转换为此尾递归循环

    let sum ret i =
                  if i == 100 then 100 + ret
                  else sum (ret+i) (i+1) in
      sum 0 1
    

    这意味着它根本不评估列表。遗憾的是,在产生程序的最终结果时,编译器无法知道值总是在NF中。然后浪费时间和RAM来保持它不被评估(形成一个thunk有成本):从一开始就更好deepseq。或者您的编译器可能存在性能错误,您必须使用seqdeepseq来帮助它。分析器会告诉您代码的哪些部分很慢。