天天看點

Haskell文法一

這裡所有的例子都在 GHC上執行通過。這是一個免費的編譯器,可以直接下載下傳,提供ghci的互交環境,和python一樣:)

首先來看一個haskell的函數:

average :: Float -> Float -> Float -> Float

average a b c = (a + b + c) / 3.0

這個函數的作用很明顯,我們關注的是它的文法形式,雙冒号之前的是函數名,之後函數的主體部分會再次重複這個名字。雙冒号之後是參數清單,用->來連接配接,最後一個float是傳回值,之前的都是參數。現在看第二行,這個是函數的定義部分,abc分别對應聲明部分三個參數,等号之後則是函數的邏輯部分。剛剛開始的時候會覺得這樣的文法十分怪異,等習慣了之後。。。還是覺得十分惡心。。。呵呵。。。

再看一個例子:

and :: Bool -> Bool -> Bool

and a b = a == b

這個函數的作用是做邏輯與操作。haskell也支援if-else-then和switch形式的語句,是以上面的函數也可以寫成:

and1 :: Bool -> Bool -> Bool

and1 a b = if a == b then True

                                   else False

and2 :: Bool -> Bool -> Bool

and2 a b | a == b = True

                 | otherwise = False

Haskell可以自己定義類型,先看一個例子:

type Colour = String

type ColourPoint = (Int, Int, Colour)

changeColour :: ColourPoint -> Colour -> ColourPoint

changeColour (x, y, oldColour) newColour = (x, y, newColour)

第一行和第二行分别定義了兩個類型,第三行開始changeColour是一個函數,接受一個point然後更改其顔色。注意定義部分,(x, y, oldColour)對應的是參數清單中的ColourPoint,newColour對應的是Colour。

引用自定義對象的時候也不一定非要指出具體的對象内容,象這樣:

equals :: ColourPoint -> ColourPoint -> Bool

equals a b = if a == b then True

                                       else False

也是可以的。另外,當對象很複雜而我們又要修改其中的值的時候,不需要把整個對象呈現出來,Haskell支援通配符幫助我們簡化代碼:

equalPos :: ColourPoint -> ColourPoint -> Bool

equalPos (a,b,_)(c,d,_)= a==c && b==d

下劃線省略了我們不關心的部分。

進一步深入之前,來看看Haskell的數組。文法和c類似,[ ]表示的是數組,不過[1,2,3,4]可以寫成[1..4],解釋器會自行翻譯。數組支援一個添加元素的操作,1:[2,3,4]的結果和上面是一樣的,冒号把元素添加到數組頭上去。這是一個例子:

enumFromTo :: Int -> Int ->[Int]

enumFromTo m n | m > n = []

                                  | otherwise = m:(enumFromTo (m+1) n)

這個函數接受兩個整數分别代表上限以及下限,傳回一個整型數組,是以enumFromTo 1 4的作用實際上和[1..4]是一樣的。注意這是一個遞歸形式的函數,實際的過程是1:2:3:4:[]。

現在來擴充一下這個函數,讓函數可以指定想前進的步數而不隻是僅僅加1:

myenumFromToBy :: Int -> Int -> Int -> [Int]

myenumFromToBy m n k | m > n = []

                                               | otherwise = m:myenumFromToBy (m+k) n k

不過這個函數隻能前進,不能後退,再改一下,我們有了第三個版本:

myenumFromToBy1 :: Int -> Int -> Int -> [Int]

myenumFromToBy1 m n k | k > 0 = myenumFromToBy m n k

                                                 | otherwise = if m<0 then []

                                                                                      else m:myenumFromToBy1 (m+k) n k

ok,這樣這個函數基本上就可以任意前進後退了。注意,上面的函數都是沒有什麼括号啊,分号之類的分隔符的。haskell和python一樣,采用layout的機制,用空格等對齊來格式代碼。是以當編譯不通過的時候,往往就是對齊的問題。目前haskell沒有什麼好的IDE可以用, UltraEdit為Haskell提供了一個文法高亮的插件,可以用用看。

下一次,我們更深入的讨論haskell的遞歸,這個是所有functional language最驕傲的特性。