1990 — Haskell 誕生#
案件摘要#
1990 年,一個國際委員會發表了 Haskell 1.0——第一個標準化的純函數式程式語言,以邏輯學家 Haskell Curry 命名。λ 演算從此不只在教科書裡,而成為可以寫出作業系統、編譯器、Web 服務的實戰語言。惰性求值、typeclass、monad——三個來自 λ 演算與範疇論的武器,全部被收編。
前因 -- 為什麼會有這個案子#
- 語言戰國時代:1980 年代純函數式語言群雄並起——David Turner 的 Miranda(1985,惰性求值)、Milner 的 ML(1978,多型型別推論)、SASL、Hope……每個都有不同的語法與語義,教學與研究無所適從。
- Miranda 的商業封鎖:Miranda 是 Turner 公司的專利軟體,大學無法自由使用——委員會需要一個開放、免費的標準語言。
- 命名懸案:Curry 的組合子邏輯(Curry–Howard 對應的來源)直接影響了函數式語言的理論基礎,委員會以 Curry 命名以致敬;Miranda 的英國血統則被一個「國際」委員會取代。
- Fergus Henderson 等委員會:1990 年版由 Paul Hudak、Philip Wadler、John Hughes、Simon Peyton Jones 等人共同設計——委員會設計是 Haskell 的獨特血統,之後每個版本(1998、2010)都經由委員會協商。
線索與推理 -- 數學式、程式、理論#
惰性求值(call-by-need)#
λ 演算有兩種求值策略: - 急切求值(call-by-value):先求值參數再應用 \((\lambda x.\,M)\,N \to (\lambda x.\,M)\,V \to M[V/x]\) - 惰性求值(call-by-need):不先求值參數,直到真的需要時才求值一次(以 thunk 快取):
Church–Rosser 定理保證:兩種策略最終結果相同(若都停機)。但惰性求值可以處理無限資料結構:
-- 無限串列:只有惰性求值才能定義!
ones = 1 : ones -- 無限個 1
nats = 0 : map (+1) nats -- 無限自然數
fibs = 0 : 1 : zipWith (+) fibs (tail fibs) -- 無限費氏數列
take 10 fibs -- [0,1,1,2,3,5,8,13,21,34]
typeclass(型別類)#
Haskell 的 typeclass 是 System F 多型的推廣——對型別做「條件約束」:
class Eq a where
(==) :: a -> a -> Bool
-- 定義:對所有屬於 Ord 的型別 a,可以排序
sort :: Ord a => [a] -> [a]
這在 λ 演算的型別系統中對應 受限量詞(bounded quantification) \(\forall a <: Eq.\, [a] \to \ldots\) ——System F 的推廣(Cardelli-Wegner 1985)。
Monad(Wadler 1992 引入)#
Haskell 是純函數式語言——沒有副作用。但列印、狀態、例外、I/O 都需要副作用!Philip Wadler 於 1992 年將範疇論的 monad 引入 Haskell,以「型別化副作用」解決這個懸案:
Monad 的三個操作(Kleisli triple,對應範疇論的 monad):
return :: a -> m a -- 單位(unit)
(>>=) :: m a -> (a -> m b) -> m b -- 綁定(bind / Kleisli extension)
Monad 三定律(對應範疇論的結合律與單位律):
return a >>= f == f a -- left identity
m >>= return == m -- right identity
(m >>= f) >>= g == m >>= (\x -> f x >>= g) -- associativity
關鍵推理:副作用被「封裝」在 monad 型別中——IO a 表示「會產生型別為 a 的結果的動作」,型別系統強制所有副作用被明確標記。這在 λ 演算中對應 Moggi 的 monadic metalanguage(1989) \(\lambda_{ml}\) :計算型 \(T A\) 與值型 \(A\) 的分離。
一個 Haskell 範例(含 lambda 與 monad)#
-- λ 演算:匿名函數(Haskell 的 \ 就來自 λ!)
double = \x -> x * 2 -- λx. 2x
add = \x y -> x + y -- λx.λy. x+y(Curry 化)
-- 高階函數:map/filter/reduce(foldr)
-- map : (a -> b) -> [a] -> [b]
-- filter : (a -> Bool) -> [a] -> [a]
-- foldr : (a -> b -> b) -> b -> [a] -> b
sumOfSquares = foldr (\x acc -> x*x + acc) 0 . filter even
-- Monad:I/O 與 lambda 的結合
main :: IO ()
main = do
let xs = map double [1..5] -- [2,4,6,8,10]
mapM_ (\x -> putStrLn ("x = " ++ show x)) xs -- monad 中用 lambda
foldr 直接對應 λ 演算的自然數歸納原理(Church numeral 的推廣):
Haskell 2010 / 2020 標準#
- Haskell 98(1999):第一個穩定標準,教科書的基礎。
- Haskell 2010(2010):加入 Foreign Function Interface、修正 semicolon 規則——最後一個官方標準。
- Haskell 2020:社群倡議(未正式發布),納入 GHC 擴充(如
LambdaCase、NumericUnderscores)。 - 實務上,GHC(Glasgow Haskell Compiler) 的擴充(type families、GADTs、rank-N types)已成為事實標準。
結案 -- 後果與影響#
- 純函數式成為主流選項:Haskell 是第一個大規模使用的惰性純函數式語言,影響了 Scala、F#、Swift、Kotlin 的函數式特性。
- monad 成為通用模式:Wadler 的 monad 影響了整個函數式程式設計——甚至 JavaScript 的 Promise、Java 的 Optional 都是 monad 的變體。「monad 是自函子(endofunctor)範疇上的幺半群」——來自 Mac Lane 的範疇論,成為程式設計師的必修知識。
- typeclass 影響了 Rust trait、Scala implicit。
- 惰性求值的雙面性:Haskell 證明了惰性求值的可行性,但也暴露了空間洩漏問題——嚴格求值(如 OCaml)在效能上反而更受歡迎。
- 工業應用:Meta 的 Sigma 反詐欺系統、金融高頻交易、編譯器(Idris、Agda 都以 Haskell 寫成)。
- 後續:Haskell 是 λ 演算與範疇論結合的最大實驗場——「Category Theory for Programmers」(Bartosz Milewski)等教材以此為基礎。
關鍵人物與文獻#
- Haskell Curry:組合子邏輯之父,Curry–Howard 對應的來源。
- Paul Hudak、Philip Wadler、John Hughes、Simon Peyton Jones:Haskell 委員會核心成員。
- 文獻:
- Hudak, P., et al. (1990). Report on the Programming Language Haskell (Yale Report).
- Wadler, P. (1992). Monads for Functional Programming (Bast van Eck lecture).
- Wadler, P., Blott, S. (1989). How to make ad-hoc polymorphism less ad hoc (typeclass 的起源).
- Peyton Jones, S. (2003). Haskell 98 Language and Libraries: The Revised Report.
- Marlow, S. (2010). Haskell 2010 Language Report.