haskell類型

1、源文件

介紹這個主要是由於下文不少代碼寫在源文件中,而後從ghci加載源文件進行測試。app

建立一個文本文件,在其中輸入,並保存爲add.hs文件函數

-- file: add.hs
add x y = x - y

打開ghci,加載剛纔的文件(假設文件目錄爲e:\haskell\add.hs),命令以下測試

ghci> :cd e:\haskell
ghci> :load add.hs
ghci> add 2 1

2、語言特性

1. 延遲計算

表達式的值在須要用到的時候才被計算,好比在一個文本文檔中輸入以下,並保存爲lazy.hsui

-- file: lazy.hs
add x y = if left || right then x + y else x -y
left = True
right = length [1..] > 0

而後加載這個文件,並執行 add 2 1,你會發現結果爲3,而不是一直等待計算結果,說明right的值並無被計算出來。在不少其餘語言中(如C#),邏輯或or被特殊處理,從而在左份量爲真的時候對右份量短路(short-circuits),而haskell中,(||)運算符只是一個普通的函數,並因爲其延遲計算的特性,致使左份量爲真的時候,右份量不被計算出來。固然了,haskell中也能夠寫出短路的邏輯或函數spa

myOr l r = if l then l else r

haskell中還有一個稱做守衛表達式的東東,上面說的myOr函數等價於設計

-- file: myOr.hs
myOr l r | l = l
myOr l r = r

2. 類型

a) 函數類型

咱們看take函數的類型code

ghci> :type take
take :: Int -> [a] -> [a]

符號->是右結合的,即,類型說明等價於orm

take :: Int -> ([a] -> [a])

b)代數數據類型

定義一個新的數據類型對象

-- file: Object.hs
data ObjectProperty = Object Int String [String]
                      deriving (Show)

這個類型ObjectProperty與三元組(Int, String, [String])的元素相同,然而haskell認爲它們類型不相同。若是要定義一個ObjectProperty類型變量,blog

ghci> let object = Object 0 "i" ["j", "k"]
ghci> :type it
it :: ObjectProperty
ghci> :type Object
Object :: Int -> String -> [String] -> ObjectProperty

分析: Object是值(數據)構造器,ObjectProperty是對象類型,固然,也能夠將對象類型與值構造器寫成相同的,如

data Object = Object Int String [String]

然而二者僅僅是名稱相同而已。

 對於Object的元素分別爲Int,String等類型,還能夠自定義這些類型的同義類型,以下

-- file: Object.hs
type ObjectId = Int
type ObjectName = String
type ObjectFields = [String]
data Object = Object ObjectId ObjectName ObjectFields

其實跟C++中的typedef關鍵字相似。

能夠查看值構造器Object的類型(是一個函數)

ghci> :type Object
Object :: ObjectId -> ObjectName -> ObjectFields -> Object

 因爲Object類型中元素是匿名的,能夠經過匹配來獲取元素值,例如

ghci> let object = Object 0 "a" ["b", "c"]
ghci> let Object x y z = object
ghci> x
0
ghci> :type x
x :: ObjectId

c)枚舉類型

-- file: Roygbiv.hs
data Roygbiv =     Red
                |  Orange
                |  Yellow
                |  Green
                |  Blue
                   deriving (Eq, Show)

其中Red、Orange等都爲值構造器

d) 記錄類型

前面簡單介紹過模式匹配。好比想內窺一下Object(前文介紹的自定義代數數據類型)的內部元素,則可使用模式匹配,咱們此次定義一個函數來獲取某個元素

getId (Object id _ _) = id
getName (Object _ name _) = name
getFields (Object _ _ fields) = fields

然而這種方法仍是顯得代碼大塊,看起來不爽。

能夠定義記錄類型,以下

-- file: Object.hs
data Object = Object {
    oid :: Int,
    oname :: String,
    ofields :: [String]
    } deriving (Show)

這個類型定義其實跟下面的形式幾乎相同

-- file: Object.hs
data Object = Object Int String [String]
                     deriving (Show)

getId :: Object -> Int
getId (Object id _ _) = id

getName :: Object -> String
getName (Object _ name _) = name

getFields :: Object -> [String]
getFields (Object _ _ fields) = fields

加載上面那個文件時,依然能夠向之前那麼使用Object類型

ghci> let object = Object 1 "az" ["b"]

或者以下使用

ghci> -- order of elements can be varied
ghci> let object = Object{oid = 10, ofields = ["i"], oname="str"}

e)參數化類型

跟C#中的泛型相似。好比定義一個類型MyMaybe以下(注意與Prelude模塊中的Maybe區分,雖然功能相似)

-- file: Maybe.hs
data MyMaybe a = MyJust a
               | MyNothing

這裏a就是參數化類型,a能夠是String或者Int等,還能夠是MyMaybe類型,即嵌套

ghci> let a = MyJust 1
ghci> let b = Just a
ghci> :type b
b :: Num a => Maybe (MyMaybe a)

f)遞歸類型

haskell中的List類型與C#中的不一樣,它是一個遞歸類型,以下

-- file: MyList.hs
data MyList a = Cons a (MyList a)
              |  Empty
                 deriving (Show)

這樣設計,使得對其進行遞歸計算方便。

 好比獲取List的首項,能夠寫成以下

-- append to the former MyList.hs file end

x = Empty
y = Cons 1 x

myHead (Cons i j) = i
myHead Empty = error "MyList.myHead: empty list"

這裏對Empty獲取首項會拋出一個錯誤,這樣處理仍是能夠的,咱們不能返回Empty,不然跟myHead的第一個計算式的返回類型不一樣(第一個計算式返回類型爲a,而Empty類型爲MyList a)。不過,若是結合Maybe類型,或者上面介紹的MyMaybe類型,則能夠避免拋出錯誤,從而使得代碼更好看些。處理以下

myHead (Cons i j) = MyJust i
myHead Empty = MyNothing
相關文章
相關標籤/搜索