Learn Haskell
這一系列博客是《Learn You a Haskell for Great Good》的讀書筆記。
一句話介紹:Haskell是一門純粹的函數式編程語言。至於什么是函數式編程?盡管網上也有很多關於函數式語言與指令式語言之間的區別與聯系,但是沒有實際使用過函數式編程語言的情況下,我也搞不清楚。因此,先從學習一門函數式編程語言開始吧。
1.安裝Haskell
要開始使用Haskell其實很簡單,只需要一個文本編輯器和一個Haskell的編譯器。目前來說最流行的Haskell的編譯器是Glasgow Haskell Compiler(GHC),我使用的就是這樣一個編譯器。
一般來說,我們會安裝Haskell Platform,因為它不僅包含了Haskell編譯器,還綁定了一下常用的庫。Haskell的官方網站是:http://www.haskell.org/haskellwiki/Haskell不管是Windows版本、Linux版本、Unix版本都有。
我使用的是Ubuntu系統,使用apt-get
安裝其實很簡單,只需要一條命令就好啦:
sudo apt-get install haskell-platform
GHC不但可以編譯Haskell腳本(.hs文件),也可以以交互式方式運行。要啟動交互模式,在終端中輸入:
ghci
這時,中斷會輸出一些信息:
GHCi, version 7.4.1: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude>
如果在Haskell文件中定義了一些函數,可以在GHC交互式解析器中輸入:
:l myFunctions
來載入你定義的函數。
2.基本算數操作
算數操作基本上和Java等其他語言都比較類似,直接舉幾個例子:
Prelude> 2 + 3
5
Prelude> 2 * 3
6
Prelude> 2 - 3
-1
Prelude> 2 / 3
0.6666666666666666
需要特別注意的事情是,在使用負數的時候,最好是使用括號,舉個例子:
Prelude> 2 * -3
<interactive>:7:1:
Precedence parsing error
cannot mix `*' [infixl 7] and prefix `-' [infixl 6] in the same infix expression
3.布爾代數
Haskell的與、或、非其實也很直接,直接看例子:
Prelude> True && False
False
Prelude> True && True
True
Prelude> True || False
True
Prelude> not False
True
判斷是否相等、是否不等:
Prelude> 2 == 3
False
Prelude> 2 /= 3
True
實際上盡管我們沒有提過函數,但是其實已經用到了函數,*
運算實際上是一個函數,它接收兩個參數,上面那種形式叫做中綴函數,但是實際上大部分函數是以前綴函數的形式調用的,下面介紹幾個:
Prelude> succ 8
9
Prelude> max 7 8
8
Prelude> min 8 9
8
Prelude> div 9 2
4
5.函數需要注意的
這幾個函數的作用非常明顯。但是需要注意的是div
函數其實等價於Java語言中的/
運算符,小數部分是舍棄的。上面的函數我們也可以以中綴函數的形式調用,比如:
Prelude> 9 `div` 2
4
我們可以定義自己的函數,函數定義的格式如下:
函數名 = 函數代碼
我們新建一個.hs文件,在其中定義一個函數:
doubleMe x = x * 2
輸入:l file.hs
,在交互式解析器中加載你所定義的函數,這時,解析器會輸出如下信息:
Prelude> :l baby.hs
[1 of 1] Compiling Main ( baby.hs, interpreted )
Ok, modules loaded: Main.
*Main>
接下來就可以使用你所定義的函數了:
*Main> doubleMe 2
4
在定義別的函數的時候可以使用已經定義的函數,例如:
doubleUs x y = x * 2 + y * 2
Haskell中也有if
表達式,但是與Java語言的if表達式有一些區別,我們先看一個例子:
doubleSmallNumber x = if x > 100 then x else x * 2
這個函數的意思是,如果一個數小於等於100,就翻倍,否則保持不變。但是需要注意的是,Haskell中的else部分是必須有的。此外還需要注意的是,Haskell函數名的首字母必須小寫。
如果函數沒有參數,那么這樣的函數在Haskell中叫做定義或者名稱。這一點有點類似於Java中的變量,但是有非常重要的區別:Haskell中的定義一旦給出就不允許改變
6.List概述
Haskell中的List是一種比較均勻整齊的數據結構,之所以說它均勻整齊是因為其中的元素必須是相同類型的。List是被方括號包裹起來的:
*Main> let nums = [1,2,3,4]
*Main> nums
[1,2,3,4]
在GHCi中需要使用let
來定義一個List。List有很多操作,下面分別介紹。
List連接操作
使用++來連接兩個List,直接看代碼:
*Main> nums ++ [5,6]
[1,2,3,4,5,6]
在Haskell中,字符串實際上就是列表,也可以使用++進行連接操作:
*Main> "Hello," ++ " " ++ "World!"
"Hello, World!"
可以使用:操作符將一個元素放到一個列表最前面:
*Main> 0 : [1,2,3] [0,1,2,3]
可以使用!!使用索引訪問List中的元素: *Main> [1,2,3,4] !! 3
4
索引號是從0開始的。
List比較大小
List比較大小的前提是List元素是可以比較的,比如說數字,比如說字母(按照字母表順序)。比較的規則是以此比較每一個元素直到出現不同的元素,那第一個不同元素,元素大的List大:
*Main> [1,2,3] < [1,2,4]
True
*Main> [1,2,3] < [1,2,3]
False
*Main> [1,2,3] < [1,2,2]
False
其他List操作
head:可以取出List的首元素;
tail:將List去掉首元素;
last:返回List的末尾元素;
init:返回除最后一個元素之前的所有元素構成的List
length:返回元素個數
null:判斷List是否為空列表
take n [...]:從列表中取出n個元素
drop n [...]:忽略n個元素后返回List
maximum/minimum:取出最大/最小值
sum:所有元素求和
product:所有元素乘積
elem:判斷元素是否在列表中
reverse:List倒置
*Main> head [1,2,3]
1
*Main> tail [1,2,3]
[2,3]
*Main> last [1,2,3]
3
*Main> init [1,2,3]
[1,2]
*Main> take 3 [1,2,3,4,5,6]
[1,2,3]
*Main> drop 3 [1,2,3,4,5,6]
[4,5,6]
*Main> length [1,2,3]
3
*Main> null []
True
*Main> reverse [1,2,3]
[3,2,1]
*Main> maximum [1,2,3]
3
*Main> minimum [1,2,3]
1
*Main> sum [1,2,3]
6
*Main> product [1,2,3]
6
*Main> 4 `elem` [1,2,3,5]
False