简体   繁体   English

为什么haskell seq函数会首先对WHNF进行论证?

[英]Why haskell seq function makes first argument to WHNF?

I thinks that seq is hard to understand because it makes first argument to WHNF. 我认为seq很难理解,因为它是WHNF的第一个论点。

If seq makes first argument to normal form, it will be easy to understand. 如果seq将第一个参数设为范式,则很容易理解。

What is the benefit of using WHNF over NF? 使用WHNF相比NF有什么好处?

Why haskell committee choose using WHNF in seq function? 为什么Haskell委员会选择在seq函数中使用WHNF?

First, Haskell's API has no preference between WHNF and NF : it provides both seq and deepseq . 首先,Haskell的API在WHNF和NF之间没有优先选择:它同时提供seqdeepseq

So maybe your question is why does WHNF exist at all ? 因此,也许您的问题是为什么WHNF根本存在? Simply put, it is the least evaluation possible. 简而言之,这是最少的评估。 A full calculation would go like this : 完整的计算将如下所示:

  1. unevaluated (thunk) 未评估(沉思)
  2. WHNF : outmost constructor known WHNF:已知的构造函数最多
  3. deeper evaluations 更深入的评估
  4. NF : the value is completely calculated NF:值已完全计算

However, Haskell is lazy, it tries to do as little calculation as possible to get its final result. 但是,Haskell很懒,它会尝试进行尽可能少的计算以获得最终结果。 For example, to compute the length of a list l , Haskell must know whether l is [] or _ : t . 例如,要计算列表l的长度,Haskell必须知道l[]还是_ : t Then recursively the same question about t . 然后递归有关t的相同问题。 Therefore it only needs the number of constructors : before the final constructor [] . 因此,它只需要数量的构造函数:在最终构造函数[] This is by definition successive WHNFs, which only extract the outmost constructor of a value. 根据定义,这是连续的WHNF,它们仅提取值的最外部构造函数。

The outmost constructor is the minimal information you must know about a value to actually do something with it, such as selecting a branch in a case of , like in length just above. 最外层的构造函数是您必须真正了解对某个值进行操作所必须知道的最少信息,例如在的case of选择一个分支,例如length恰好在上面。 That is the interest of WHNF over NF. 这是WHNF胜过NF的兴趣。

Note that for simple types like Int , each value is its own constructor ( 2 , -7 , 15 , ...), so WHNF = NF for them. 请注意,对于简单的类型,如Int ,每个价值是自身的构造函数( 2-715 ,......),所以WHNF = NF他们。

Finally, you rarely care about all this : it is the compiler's job to execute your program as fast as possible. 最后,您几乎不需要关心所有这一切:尽可能快地执行程序是编译器的工作。 In the evaluation of foldl (+) 0 [1..100] , if you try to figure out when the list [1..100] finishes in NF you will be completely wrong. 在对foldl (+) 0 [1..100]的求值中,如果您试图弄清楚列表[1..100]在NF中完成的时间,那将是完全错误的。 The compiler transforms that fold into this tail-recursive loop 编译器将此折叠转换为该尾递归循环

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

which means it doesn't evaluate the list at all. 这意味着它根本不会评估列表。 Unfortunately there are situations where the compiler cannot know that a value will always be in NF when the final result of the program is produced. 不幸的是,在某些情况下,当生成程序的最终结果时,编译器无法知道某个值将始终位于NF中。 Then it is a waste of time and RAM to keep it unevaluated (forming a thunk has a cost) : better deepseq it right from the start. 然后,浪费时间和RAM使其保持deepseq (形成deepseq东西deepseq ):从一开始就更好地进行deepseq Or your compiler may have performance bugs and you must help it with seq or deepseq . 否则您的编译器可能会出现性能错误,因此您必须使用seqdeepseq帮助它。 A profiler will tell you what parts of your code are slow. 探查器将告诉您代码的哪些部分运行缓慢。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM