参考:https://stackoverflow.com/questions/6872898/haskell-what-is-weak-head-normal-form
Normal form:
An expression in normal form is fully evaluated, and no sub-expression could be evaluated any further (i.e. it contains no un-evaluated thunks).
These expressions are all in normal form:
42
(2, "hello")
\x -> (x + 1)
These expressions are not in normal form:
1 + 2 -- we could evaluate this to 3
(\x -> x + 1) 2 -- we could apply the function
"he" ++ "llo" -- we could apply the (++)
(1 + 1, 2 + 2) -- we could evaluate 1 + 1 and 2 + 2
Weak head normal form
An expression in weak head normal form has been evaluated to the outermost data constructor or lambda abstraction (the head). Sub-expressions may or may not have been evaluated. Therefore, every normal form expression is also in weak head normal form, though the opposite does not hold in general.
WHNF的定义:An expression如果是下面中的一种,则in weak head normal form:
- a constructor (eventually applied to arguments) like True, Just (square 42) or (:) 1(注意True是Bool的一个Constructor, (:) 1是列表的一个Constructor)
- a built-in function applied to too few arguments (perhaps none) like (+) 2 or sqrt.
- or a lambda abstraction \x -> expression.
To determine whether an expression is in weak head normal form, we only have to look at the outermost part of the expression. If it's a data constructor or a lambda, it's in weak head normal form. If it's a function application, it's not.
These expressions are in weak head normal form:
(1 + 1, 2 + 2) -- the outermost part is the data constructor (,)
\x -> 2 + 2 -- the outermost part is a lambda abstraction 这只是一个lambda抽象
'h' : ("e" ++ "llo") -- the outermost part is the data constructor (:)
As mentioned, all the normal form expressions listed above are also in weak head normal form.
These expressions are not in weak head normal form:
1 + 2 -- the outermost part here is an application of (+),它是函数应用,不是Constructor
(\x -> x + 1) 2 -- the outermost part is an application of (\x -> x + 1) 这里lambda函数是函数应用,不是一个lambda抽象,注意和上面的区别(当然,如果提供的实参少,则又是WHAT)
"he" ++ "llo" -- the outermost part is an application of (++) ++在这里是函数应用
WHNF特点是:参数只计算到第一个 data constructor,它不会把整个值一次全部算出来。
比如 Just (square 42) is WHNF,它不会有进一步的计算
又如 (+) (2 * 3 * 4)也是一个 WHNF,尽管 (2 * 3 * 4)能被简化为标准格式24.
例1
ghci> let t = const (Just "hello") ()
ghci> :sprint t
t =\_
ghci> seq t ()
()
ghci> :sprint t
t = Just _
例2(注意多态)
多态值在被赋予具体的类型前是不会被计算的,即使用seq也不行;
ghci> data F a = SomeVal a
ghci> let t = SomeVal 3 :: F Int
ghci> :sprint t
t = 3
注意下面是多态,类型不确定
ghci> let t = SomeVal 3
ghci> :sprint t
t = _
两者上面两个例子的区别在于前者类型是确定的
—————————————————————
下面仍然要注意泛型和非泛型的区别
ghci> let t = const (SomeVal 3) ()
ghci> :sprint t
t = \_
ghci> seq t ()
()
ghci> :sprint t
t = _
ghci>
ghci> let t = const (SomeVal 3) () :: F Int
ghci> :sprint t
t = _
ghci> seq t ()
()
ghci> :sprint t
t = 3