Haskell是一種標準化的，通用的純函數語言程式設計語言，有惰性求值和強靜態型別 Haskell Report。它的命名源自美國邏輯學家哈斯凱爾加里，他在數理邏輯方面上的工作使得函數語言程式設計語言有了廣泛的基礎。在 Haskell 中，函式是頭等物件。作為一門函式程式語言，主要控制結構是函式。Haskell 語言是 1990 年在程式語言 Miranda 語言的基礎上標準化的，並且以 λ 演算為基礎發展而來。這也是為什麼 Haskell 語言以希臘字母「λ」（Lambda）作為自己的標誌。Haskell 具有 證明即程式、命題為型別 的特徵，with 2 sections by William Craig see paragraph 9E Reprinted in revised form with two pages commentary in 。 歷史 1985 年，Miranda 發行後，惰性函式式語言的關注度增長。到 1987 年前，出現了十多種、純函式式語言。其中，Miranda 使用的最為廣泛，但還沒有出現在公共領域。在俄勒岡波特蘭的函數語言程式設計語言與計算機結構大會（FPCA 87）上，參加者一致同意形成一個委員會來為這樣的語言定義一種開源標準。該委員會旨在整合已有函式式語言，作為將來的函式式語言設計研究工作的基礎。 Haskell 10 至 14 能夠確使型別安全的運算子過載的型別類，是由 Philip Wadler 和 Stephen Blott 最初為 Standard ML 提議的，但首先在 Haskell 中於 1987 年至版本 10 期間實現 Type classes first proposed during the design of the Haskell programming language John Garrett Morris 2013 Type Classes and Instance Chains A Relational Approach 。 1990 年定義了 Haskell 的第一個版本（Haskell 10）。委員會形成了一系列的語言定義（10，11，12，13，14）。 Haskell 98 1997 年底，該系列形成了 Haskell 98，旨在定義一個穩定、最小化、可移植的語言版本以及相應的標準庫，以用於教學和作為將來擴充套件的基礎。委員會明確歡迎建立各種增加或整合實驗性特性的 Haskell 98 的擴充套件和變種。 1999 年 2 月，Haskell 98 語言標準公佈，名為《The Haskell 98 Report》。2003 年 1 月，《Haskell 98 Language and Libraries The Revised Report》公佈。接著，格拉斯哥 Haskell 編譯器實現了當時的事實標準，Haskell 快速發展。 Haskell Prime 2006 年早期，開始了定義 Haskell 98 標準後續的程序，非正式命名為 Haskell Prime。這是個修訂語言定義的不斷增補的過程，每年產生一個新的修訂版。第一個修訂版於 2009 年 11 月完成、2010 年 7 月釋出，稱作 Haskell 2010。 Haskell 2010 Haskell 2010 加入了外部函式介面（，FFI）允許繫結到其它程式語言，修正了一些語法問題（在正式語法中的改動）並廢除了稱為 n 加 k 模式（換言之，不再允許形如 fact n1 n1 fact n 的定義）。引入了語言級編譯選項語法擴充套件（LanguagePragmaSyntaxExtension），使得在 Haskell 原始碼中可以明確要求一些擴充套件功能。Haskell 2010 引入的這些擴充套件的名字是 DoAndIfThenElse、HierarchicalModules、EmptyDataDeclarations、FixityResolution、ForeignFunctionInterface、LineCommentSyntax、PatternGuards、RelaxedDependencyAnalysis、LanguagePragma、NoNPlusKPatterns。 特性 Haskell 是現有的一門開放的、已釋出標準的，且有多種實現的語言。支援惰性求值、模式匹配、列表解析、型別類和型別多型。它是一門純函數語言程式設計語言，這意味著大體上，Haskell 中的函式沒有副作用。Haskell 用特定的型別來表達副作用，該型別與函式型別相互獨立。純函式可以操作並返回可執行的副作用的型別，但不能夠執行它們，只有用於表達副作用的型別才能執行這些副作用，Haskell 以此表達其它語言中的非純函式。 Haskell 擁有一個基於 HindleyMilner 型別推論的靜態、強型別系統。Haskell 在此領域的主要創新就是加入了型別類，原本設想作為過載的主要方式，在之後發現了更多用途。 Haskell 的主要實現 GHC 是個直譯器，也是個原生程式碼編譯器。它可以在大多數平臺執行，GHC 在併發和並行上具有高效能的實現能力，也有豐富的型別系統，如和）。 單子是一個抽象型別，可以表達不同種類的計算，包括異常處理、非確定性、語法分析以及軟體事務記憶體，其中一個應用是用於表達副作用的型別。單子定義為普通的資料型別，同時 Haskell 也為其提供了幾種語法糖。 Haskell 有一個活躍的社群，在線上包倉庫 Hackage 上有豐富的第三方開源庫或工具。 語法 資料型別 Haskell 是強型別語言。Char 的字面值用單引號圍起；字串即 Char 型別，其字面值用雙引號括起來。Int 通常為 32 位整型；Integer 是無界整型；Float 表示單精度的浮點數；Double 表示雙精度的浮點數；Bool 只有兩種值：True 和 False。 List 使用 與逗號分隔符，定義一個 list 的例項。其元素必須具有相同型別。字串是 list 的特例。用：把元素與 list、其他元素連線（cons）起來。 是右結合的運算子。123 實際上是 123 的語法糖。兩個 List 合併透過 運運算元實現。按照索引取得 List 中的元素，可以使用！運運算元，索引的下標為 0。List 中的 List 可以是不同長度，但必須得是相同的型別。KZ 這樣的 Range 方法快捷定義一個 List。2420 用法給出了 Range 的第一、第二、最後一個元素。使用 和 可以比較 List 的大小。它會先比較第一個元素，若它們的值相等，則比較下一個，以此類推。List 常用的函式 head 返回一個 List 的頭部，也就是 List 的首個元素。 tail 返回一個 List 的尾部，也就是 List 除去頭部之後的部分。 last 返回一個 List 的最後一個元素。 init 返回一個 List 除去最後一個元素的部分。 length 返回一個 List 的長度。 null 檢查一個 List 是否為空。如果是，則返回 True，否則返回 False。 reverse 將一個 List 反轉 take 返回一個 List 的前幾個元素。例如 take 24 1326 取前 24 個 13 的倍數 drop 刪除一個 List 中的前幾個元素 maximum 返回一個 List 中最大的元素。 minimun 返回最小的元素。 sum 返回一個 List 中所有元素的和。 product 返回一個 List 中所有元素的積。 elem 判斷一個元素是否在包含於一個 List，通常以中綴函式的形式呼叫 replicate 得到包含相同元素的 List 。例如：replicate 3 10，得 101010。 repeat 產生一個元素的無限重複的 List cycle 接受一個 List 做引數並返回一個無限 List list comprehension 是指基於一個 List，按照規則產生一個新 List，例如：x2 x 110 x2 12 Tuple 使用 與逗號分隔符，定義一個 tuple 的例項。其元素可以使不同型別，但個數是固定的。 Tuple 的型別取決於其中項的數目與其各自元素的型別。單元素的 Tuple 被禁止。 fst 返回一個序對的首項。 snd 返回序對的尾項 zip 取兩個 List 作為引數，然後將它們依次配對，形成一組序對的 List。 運算子 基本類似於 C 語言。但使用 not 表示邏輯非。 加、減、乘、除、指數 mod 取餘數 也是表示函式作用的，但它的優先順序最低，而且作用次序是從右向左的 兩個 List 的連線 函式的複合 與、或、等於、不等於 小於等於、大於等於、小於、大於 一個元素連線 List、 函式型別描述，運算子左邊為引數型別，右邊為結果型別。為右結合。例如：addThree Int Int Int Int 運算子的左邊表示一個型別變數（通常為單個小寫字母）屬於一個型別類（Typeclass），相當於 C 語言的模板引數型別 List 的 Range 限定 函式 表示式的型別特徵，左側為函式 表示式，右側為型別 List comprehension 的條件限定 取 List 的第某個元素，下標從 0 開始 基本的 Typeclass： Eq 可判斷相等性的 type Ord 可比較大小的 type Show 可表示為字串的 type Read 可從字串轉換出值的 type Enum 連續的，也就是可列舉的 type。每個值都有後繼 successer 和前置 predecesor，分別可以透過 succ 函式和 pred 函式得到。 Bounded 有上限和下限。例如：maxBound Char 或者 maxBound Bool Num 數字 Integral Floating 表示式 let 表示式：格式為 let bindings in expressions 。let 也可以定義區域性函式 。在一行中設定多個名字的值，可用分號隔開。List Comprehension 中 let 繫結的名字在輸出函式及限制條件中都可見；忽略了 let 繫結的 in 部分，因為名字的可見性已經預先定義好了。 if then else 是表示式 Case 表示式： case expression of pattern result pattern result pattern result 控制結構 if then else 是分段函式定義時的語法糖。與 C 語言不同，要求必須有 else 部分。類似於 C 語言分支語句的情形，叫做 pattern matching，例子如下： pts Int Int pts 1 10 pts 2 6 pts x x 6 7 x otherwise 0 Bool Bool Bool 或操作的型別與定義 True _ True 第二個引數是任何值都匹配。 False y y 函式 函式呼叫有最高運算順序，例如 succ 910 表示 succ 910。 函式的呼叫使用空格符而不是括號。 函式的複合呼叫是左結合。 首字母大寫的函式是不允許的。 兩個引數的函式的呼叫可以寫成中綴形式：param1 funcName param2。 運算子可以用括號圍起來，作為字首形式： 2 3 的結果為 5。 在 ghci 下，我們可以使用 let 關鍵字來定義一個常量。在 ghci 下執行 let a1 與在指令碼中編寫 a1 是等價的。 funcName arguments expression 定義函式的一般形式 area r pi r 2 定義了一個函式 area 101 呼叫了函式 f1 f2 314 函式呼叫是左結合，等效於 f1 f2 314 模式匹配方式定義 factorial Integral a a a factorial 0 1 factorial n n factorial n 1 as 模式，是將一個名字和 置於模式前，可以在按模式分割引數值時仍保留對其整體的引用。如 nameGlobalxyys，nameGlobal 會匹配出與 xyys 對應的東西。as 模式在較大的模式中保留對整體的引用，從而減少重複性的工作。 heron a b c sqrt s s a s b s c where where 在表示式中區域性綁定了名字 s 與一個值。也可以在表示式之前用 let in 語法 s a b c 2 absolute x 絕對值函式，使用了分段函式語法糖（稱作 Guards） x 0 0 x otherwise x 兜底條件 bmiTell RealFloat a a a String bmiTell weight height bmi 185 Youre underweight bmi 250 Youre normal bmi 300 Youre fat otherwise Youre overweight where bmi weight height 2 使用 where 定義多個名字來避免重複 where 也可以用模式匹配 initials String String String initials firstname lastname f l where f_ firstname l_ lastname where 可以定義函式。在定義一個函式的時候也寫幾個輔助函式擺在 where 繫結中。 而每個輔助函式也可以透過 where 擁有各自的輔助函式。 calcBmis RealFloat a a a a calcBmis xs bmi w h w h xs where bmi weight height weight height 2 funcName type1 type2 type3 其中， 表示型別特徵 type signature， 是右結合，這裡等效於 type1 type2type3，給定一個 type1 的輸入引數，返回一個函式 type2type3 f1 absolute area 函式複合運算子是 function composition operator 多型型別 Polymorphic types 類似於 C 的模板。例如，算術加法： Num a a a a Num 是 typeclass。 表示 signature restricts lambda 函式 lambda 就是匿名函式。寫法是：一個 （因為它看起來像是希臘字母 λ），後面是用空格分隔的引數， 後面是函式體。通常用括號將括起 lambda 函式，否則它會佔據整個右邊部分。 例如：a b a 30 3 b 可以在 lambda 中使用模式匹配，但無法為一個引數設定多個模式，如 和 xxs 並用。 使用 lambda 可以更明確地表現出值是個函式，可以用來傳遞給其他函式作引數。 高階函式 Haskell 的所有函式實際上是單引數函式。多引數函式的寫法實際上是 Curry 化的語法糖。即 func a b 等價於 func a b。 point free style 也稱作 pointless style 的函式，即透過柯里化 Currying 省略掉單引數。例如： sum Num a a a sum xs foldl 0 xs 等號的兩端都有個 xs。 sum foldl 0 柯里化 Currying，可以省掉兩端的 xs。 中綴運算子可以加括號變為單引數函式。如 3 5 的值為 15。 但 5 表示負值，所以單引數函式需要寫為 subtract 5。 中綴運算子 可用於改變函式的呼叫次序，使其右邊的表示式先計算出來。這可以減少一對括號使用。例如 f g z x 與 f g z x 等價。其定義是： a b a b f x f x 還可以將資料作為函式使用。例如： map 3 4102sqrt 中綴運算子。用於函式的複合，其定義是： b c a b a c f g x f g x 異常處理 提供了處理異常的函式、、 import Prelude hiding catch import ControlException instance Exception Int instance Exception Double main do catch catch throw 42Int e print 0eDouble e print 1eInt 輸出結果 142 類似於 C include iostream using namespace std int main try throw int 42 catch double e cout 0 e endl catch int e cout 1 e endl 另外一個例子： do Statements in which errors might be thrown catch ex do Statements that execute in the event of an exception with ex bound to the exception 如果僅有一個錯誤條件， 類足夠用了，確省是 Haskell 的。更復雜的出錯處理用 或 monads 類似功能可用。 示例 Haskell 的函式結構 如下是 Haskell 語言的 Hello world，注意其中除最後一行外皆可省略。 module Main where main IO main putStrLn Hello World 如下是階乘函式的 Haskell 實現： fac Int Int fac 0 1 fac n n fac n 1 它將階乘描述成有一個基本終止情形的遞迴函式。這跟數學定義中對階乘的描述很相似。事實上，Haskell 中很多的程式碼的語法與功能都和數學一致。 上面的遞迴函式的第一行是可選的，它描述了這個函式的型態（types）。它可以讀作函式 fac 的型態為整數至整數（function fac has a inttoint type）。這就是說，它以一個整型為引數，並且返回另一個整型。 第二行依賴的模式匹配，是 Haskell 程式中一個重要的部分。注意函式的引數是用空格分隔而不是在括號中。當函式的引數是 0 時，它會返回整型 1。對於其他的情況則嘗試第三行。這是一個遞迴，它會一直執行只到滿足基本的情形。負引數會導致無限遞迴，一個保證第三行不會執行負引數。 Prelude 是一個類似 C 中標準庫的小函式集合。使用 Prelude，並用無指定引數的寫法，它可以改成： fac product enumFromTo 1 上面的定義接近於數學中的定義：f g o h（參見複合函式），這並不是一個對變數賦值的語句。 Haskell 的高階函式 Haskell 中可以定義高階函式（Higherorder Function），既將函式作為一個引數來使用，也可以將函式作為結果輸出，例如： f Int Int Int Int f g x g x 5 這裡 f 就是一個高階函式，它取一個從 Int 到 Int 的函式 g 作為引數，輸出一個從 Int 到 Int 的函式。高階函式的使用在一些情況下將極大的簡化程式碼。 Haskell 的編譯器 Hugs ghc Glasgow Haskell Compiler yhc York Haskell Compiler nhc98 參考文獻 外部連結 Haskell 的官方主頁 HaskellWiki：Haskell 社群主網站 UNSW 的 Haskell 教程 Haskell 笑話 Haskell 舊的討論主題 Haskell vs Ada vs C vs Awk vs 一個實驗性的前衛語言（PostScript 檔案） Haskell 程式設計的變革 一個輕快的 Haskell 程式設計風格總纜 一個 Haskell 研究者的線上介紹 ePolyglot 將 Haskell、Python 與 Eiffel 結合的語言 Haskell 函式庫 教學手冊 用 Haskell 寫程式，Graham Hutton 撰寫 另一個 Haskell 教學手冊 由 Hal Daume III 所寫的好手冊，需要比官方教學手冊少的先備知識 A Gentle Introduction to Haskell 98（較高階的教學手冊，有 PDF 檔案） Haskell Tutorial for C Programmers，Eric Etheridge 撰寫 在 Haskellorg 的教學手冊列表 Haskell 程式設計典範 Haskell 趣學指南 Haskell 趣學指南 Category 靜態型別程式語言 Category 函數語言程式設計語言 Category 模式匹配程式語言 Category 學術的程式語言 Category1990 年建立的程式語言