筆記:Haskell函數語言程式設計入門 - 惰性求值簡介

漆楚衡發表於2014-07-29

λ演算簡介

定義:Expression -> Constant | Variable | Expression Expression | λ Variable. Expression

α替換:λx.λy.x + y ≡ λa.λy.a + y (不出現命名衝突的情況下的重新命名)

β化簡:(λx.M) N -> [x / N] M (應用時“實參”到“形參”的替換過程)

η化簡:(λx.M) x -> M (似乎只是文字意義上的一種簡化)


⊥(Bottom)

⊥用於表示計算沒有結果(沒有β-nf)的表示式的語義,下面用Haskell中的unedfined作為一個⊥的例項。

每一個ADT都有一個額外的值:“⊥”,但newtype型別不會追加“⊥”

例:

有型別定義:

newtype N = N Int
data D = D Int

函式定義:

n (N i) = 42
d (D i) = 42

有如下應用:

n undefined
d undefined

結果為

42
undefined

可以認為newtype定義的型別(N)和它的第一個值構造子所容納的型別(Int)的是同構的,newtype不追加“⊥”的原因也是為了這種同構,但是一個接受N型別的函式也可能有“⊥”作為輸入,這時參考根據上面同構的想法,可以很自然的理解newtype會把“⊥”“轉嫁”給自己包裹的型別,於是undefined被“轉嫁”給i,而i不必被求值,於是第一個函式返回42。 (對newtype的解釋主要來自這裡

而d因為模式匹配要對傳入引數進行計算,即使i的值無所謂,但還是要計算D值構造子,於是會對undefined進行計算,結果就undefined了。

當函式引數為⊥時,如果函式結果為⊥(⊥在語法上是有型別的,但在語義上我們不區分),稱函式嚴格,否則非嚴格。E.g. n是非嚴格的,d是嚴格的。

d (D undefined) --undefined為Int型別的一個值,故函式返回42(沒有對D值構造子計算內容)。
d' (D !i) = 42 --如果想要求值構造子的引數,型別前加“!”。

seq 以及 $!

seq : : a -> b -> b --會直接返回第二個引數,但會對第一個引數嚴格計算。
($!) :: (a -> b) -> a -> b --同($)但會嚴格計算第二個引數。  

表示式形態和thunk

WHNF:

形如F M1 M2 M3 的表示式

  1. F為常量(值,內建函式,值構造子)
  2. F為λ表示式,但後跟M1到Mn不能使其完全應用而導致不能化簡。

    • 表示式可以寫成樹狀結構,此處的F為頂層,由於它引數不夠,內部子樹不必計算。
    • 總結為表示式樹的頂層無法化簡時,表示式為WHNF。

HNF:為WHNF真子集

形如λx1.λx2. ... λxn.(v M1 M2 ... Mm)

  1. (v M1 M2 ... Mm) :同WHNF1.
  2. 當λ部分退化時,即為(v M1 M2 ... Mm).
  3. 否則, 要求完全β化簡,即不允許WHNF中的外圍(F後的)M1到Mn,並且F的引數巢狀層同樣要求如此
    • λx.(λy.y + x) 3 :此處(λy.y + x) 3可以繼續化簡。不為HNF。
    • λx.x ((λy.y) 5) :此處處於λ的內部表示式(v M1 M2 ... Mm),不作要求,為HNF。

NF:為HNF的真子集

  • 表示式的任意部分都完全化簡。
  • 相對於上面兩個,主要是(v M1 ... Mn)部分,NF要求Mx本身是最簡的。

沒搞清的地方

內建函式何時求值?

  • 以上三者都是定義在lambda操作上的化簡,內建函式何時求值? 作者說seq會將表示式求值到HNF,(+) 1 1 應為HNF(甚至NF),但是seq會將其求值為2。

相關文章