基本介紹
Haskell(發音為/ˈhæskəl/)是一種标準化的,通用純函數式編程語言,有非限定性語義和強靜态類型。它的命名源自美國邏輯學家Haskell Brooks Curry,他在數學邏輯方面的工作使得函數式編程語言有了廣泛的基礎。在Haskell中,“函數是一等公民”。作為函數式編程語言,主要控制結構是函數。Haskell語言是1990年在編程語言Miranda的基礎上标準化的,并且以λ演算(Lambda-Calculus)為基礎發展而來。具有“證明即程序、結論公式即程序類型”的特征。這也是Haskell語言以希臘字母「λ」(Lambda)作為自己标志的原因。Haskell語言的最重要的兩個應用是GHC(Glasgow Haskell Compiler)和Hugs(一個Haskell語言的解釋器)。
曆史
1985年,Miranda發行後,惰性函數式語言的關注度增長。到1987年前,出現了十多種非限定性、純函數式語言。其中,Miranda使用的最為廣泛,但還沒有出現在公共領域。在俄勒岡波特蘭的函數式編程語言與計算機結構大會(FPCA'87)上,參加者一緻同意形成一個委員會來為這樣的語言定義一種開放性标準。該委員會旨在集成已有函數式語言,作為将來的函數式語言設計研究工作的基礎。
Haskell 1.0至1.4
1990年定義了Haskell的第一個版本(“Haskell1.0”)。委員會形成了一系列的語言定義(1.0,1.1,1.2,1.3,1.4)。
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》公布。接着,Glasgow Haskell Compiler (GHC)實現了當時的事實标準,Haskell快速發展。
Haskell Prime
2006年早期,開始了定義Haskell 98标準後續的進程,非正式命名為Haskell Prime。這是個修訂語言定義的不斷增補的過程,每年産生一個新的修訂版。第一個修訂版于2009年11月完成、2010年7月發布,稱作Haskell 2010。
Haskell 2010
Haskell 2010加入了外部函數接口(Foreign Function Interface,FFI)允許綁定到其它編程語言,修正了一些語法問題(在正式語法中的改動)并廢除了稱為“n加k模式”(換言之,不再允許形如fact(n+1)=(n+1)*factn的定義)。引入了語言級編譯選項語法擴展(Language-Pragma-Syntax-Extension),使得在Haskell源代碼中可以明确要求一些擴展功能。Haskell 2010引入的這些擴展的名字是DoAndIfThenElse、HierarchicalModules、EmptyDataDeclarations、FixityResolution、ForeignFunctionInterface、LineCommentSyntax、PatternGuards、RelaxedDependencyAnalysis、LanguagePragma、NoNPlusKPatterns。
特性
Haskell是現有的一門開放的、已發布标準的,且有多種實現的語言。支持惰性求值、模式匹配、列表解析、類型類和類型多态。它是一門純函數編程語言,這意味着大體上,Haskell中的函數沒有副作用。Haskell用特定的類型來表達副作用,該類型與函數類型相互獨立。純函數可以操作并返回可執行的副作用的類型,但不能夠執行它們,隻有用于表達副作用的類型才能執行這些副作用,Haskell以此表達其它語言中的非純函數。
Haskell擁有一個基于Hindley-Milner類型推論的靜态、強類型系統。Haskell在此領域的主要創新就是加入了類型類(type class),原本設想作為重載的主要方式,在之後發現了更多用途。
Haskell的主要實現GHC是個解釋器,也是個原生代碼編譯器。它可以在大多數平台運行,GHC在并發和并行上具有高性能的實現能力,也有豐富的類型系統,如廣義代數數據類型和類型族(Type Families)。
單子是一個抽象類型,可以表達不同種類的計算,包括異常處理、非确定性、語法分析以及軟件事務内存,其中一個應用是用于表達副作用的類型。單子定義為普通的數據類型,同時Haskell也為其提供了幾種語法糖。
Haskell有一個活躍的社區,在線上包倉庫Hackage上有豐富的第三方開源庫或工具。
語法
數據類型
Haskell是強類型語言。Char的字面值用單引号圍起;字符串即[Char]類型,其字面值用雙引号括起來。Int通常為32位整型Integer是無界整型Float表示單精度的浮點數Double表示雙精度的浮點數Bool隻有兩種值:True和False。
List
使用[ ]與逗号分隔符,定義一個list的實例。其元素必須具有相同類型。字符串是list的特例。用:把元素與list、其他元素連接(cons)起來。:是右結合的運算符。[1,2,3]實際上是1:2:3:[]的語法糖。兩個List合并通過++運算符實現。按照索引獲取List中的元素,可以使用。運算符,索引的下标為0。List中的List可以是不同長度,但必須得是相同的型别。['K'..'Z']這樣的Range方法快捷定義一個List。[2,4..20]用法給出了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[13,26..]取前24個13的倍數
drop删除一個List中的前幾個元素
maximum返回一個List中最大的元素。
minimun返回最小的元素。
sum返回一個List中所有元素的和。
product返回一個List中所有元素的積。
elem判斷一個元素是否在包含于一個List,通常以中綴函數的形式調用
replicate得到包含相同元素的List。例如:replicate 3 10,得[10,10,10]。
repeat産生一個元素的無限重複的List
cycle接受一個List做參數并返回一個無限List
list comprehension是指基于一個List,按照規則産生一個新List,例如:[x*2|x<-[1..10],x*2>=12]
Tuple
使用( )與逗号分隔符,定義一個tuple的實例。其元素可以使不同類型,但個數是固定的。
Tuple的類型取決于其中項的數目與其各自元素的類型。單元素的Tuple被禁止。
fst返回一個序對的首項。
snd返回序對的尾項
zip取兩個List作為參數,然後将它們依次配對,形成一組序對的List。
運算符
基本類似于C語言。但使用not表示邏輯非。
基本的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表達式:
控制結構
if then else是分段函數定義時的語法糖。與C語言不同,要求必須有else部分。類似于C語言分支語句的情形,叫做pattern matching,例子如下:
函數
函數調用有最高運算順序,例如succ 9*10表示(succ 9)*10。
函數的調用使用空格符而不是括号。
函數的複合調用是左結合
首字母大寫的函數是不允許的
兩個參數的函數的調用可以寫成中綴形式:param1 `funcName` param2
運算符可以用括号圍起來,作為前綴形式:(+) 2 3的結果為5
在ghci下,我們可以使用``let``關鍵字來定義一個常量。在ghci下執行 ``let a=1`` 與在腳本中編寫 ``a=1``等價的
多态類型(Polymorphic types)類似于C++的模闆。例如,算術加法:
lambda函數
lambda就是匿名函數。寫法是:一個 (因為它看起來像是希臘字母λ),後面是用空格分隔的參數,->後面是函數體。通常用括号将括起lambda函數,否則它會占據整個右邊部分。
例如:(a b -> (a * 30 + 3) / b)
可以在lambda中使用模式匹配,但無法為一個參數設置多個模式,如 [] 和 (x:xs)并用。
使用lambda可以更明确地表現出值是個函數,可以用來傳遞給其他函數作參數。
高階函數
Haskell的所有函數實際上是單參數函數。多參數函數的寫法實際上是Curry化的語法糖。即func a b等價于(func a) b
point free style(也稱作 pointless style)的函數,即通過柯裡化(Currying)省略掉單參數。例如:
中綴運算符可以加括号變為單參數函數。如(*3) 5 的值為15 但(-5)表示負值,所以單參數函數需要寫為(subtract 5)。
中綴運算符$,可用于改變函數的調用次序,使其右邊的表達式先計算出來。這可以減少一對括号使用。例如f (g (z x)) 與 f $ g $ z x 等價。其定義是:
$還可以将數據作為函數使用。例如:
中綴運算符.用于函數的複合,其定義是:
異常處理
提供了處理異常的函數Template:Haskell/Template:Haskell/Template:Haskell/Template:Haskell.
輸出結果
類似于C++
另外一個例子:
如果僅有一個錯誤條件,Template:Haskell類足夠用了,确省是Haskell的Template:Haskellclass.更複雜的出錯處理用Template:Haskell或Template:Haskellmonads,類似功能可用Template:Haskell。
語言
以Haskell為基礎的衍生語言有很多種,它們分别是:并行Haskell,擴充Haskell(舊名Goffin),Eager Haskell, Eden,DNA-Hakell 和面向對象的變體(Haskell++,O'Haskell,Mondrian)。另外Haskell還被作為其他語言設計新功能時的樣闆,例如Python中的Lambda标記語句。