有關Weak Head Normal Form

weixin_34308389發表於2018-08-08

參考: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 = <SomeVal> 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 = <SomeVal> 3

相關文章