head 函数的类型的类型如下:
ghci> :t head
head :: [a] -> a
让我们来研究下 == 函数的类型声明:
ghci> :t (==)
(==) :: (Eq a) => a -> a -> Bool
Note: 判断相等的==运算符是函数,+-*/
之类的运算符也是同样。在缺省条件下,它们多为中缀函数。若要检查它的类型,就必须得用括号括起使之作为另一个函数,或者说以首码函数的形式调用它。
ghci> read "5" :: Int
5
ghci> read "(3, 'a')" :: (Int, Char)
(3, 'a')
或者根据read 后跟的那部分,ghci自动辨认类型。
ghci> read "True" || False
True
ghci> read "8.2" + 3.8
12.0
ghci> succ 'B'
'C'
ghci> [LT .. GT]
[LT,EQ,GT]
ghci> minBound :: Int
-2147483648
ghci> maxBound :: Char
'\1114111'
ghci> maxBound :: Bool
True
ghci> minBound :: Bool
False
另外,如果Tuple中所有项都属于Bounded的Typeclass,那么它也属于Bounded。
Note:fromIntegral函数用于处理数字,其类型声明为: fromIntegral :: (Num b, Integral a) => a -> b。将一个整数变为更广泛的类型num。
data Bool = False | True
data = 的左端标明类型的名称即 Bool,= 的右端就是值构造子 (Value Constructor),它们明确了该类型可能的值。| 读作"或"
以上可以理解为:Bool 类型的值可以是 True 或 False。
data Shape = Circle Float Float Float
值构造子本质函数,可以返回一个类型的值,如下类型声明。
ghci> :t Circle
Circle :: Float -> Float -> Float -> Shape
由于值构造子是个函数,因此我们可以拿它交给 map,拿它不全调用,以及普通函数能做的一切。
ghci> map (Circle 10 20) [4,5,6,6]
[Circle 10.0 20.0 4.0,Circle 10.0 20.0 5.0,Circle 10.0 20.0 6.0,Circle 10.0 20.0 6.0]
data Shape = Circle Float Float Float | Rectangle Float Float Float Float deriving (Show)
之后Haskell 就会自动将该类型至于 Show 类型类之中。
module Shapes
( Shape(..),
···
)where
data Person = Person { firstName :: String
, lastName :: String
, age :: Int
, height :: Float
, phoneNumber :: String
, flavor :: String
} deriving (Show)
data Car = Car String String Int deriving (Show)
ghci> Car "Ford" "Mustang" 1967
Car "Ford" "Mustang" 1967
data Car = Car {company :: String, model :: String, year :: Int} deriving (Show)
类型构造子可以取类型作参数,产生新的类型。
data Maybe a = Nothing | Just a
这里的a就是个类型参数。也正因为有了它,Maybe 就成为了一个类型构造子。在它的值不是 Nothing 时,它的类型构造子可以搞出 Maybe Int,Maybe String 等等诸多态别。
data Person = Person { firstName :: String
, lastName :: String
, age :: Int
} deriving (Eq, Show)
let mikeD = Person {firstName = "Michael", lastName = "Diamond", age = 43}
ghci> mikeD
Person {firstName = "Michael", lastName = "Diamond", age = 43}
ghci> let mikeD = Person {firstName = "Michael", lastName = "Diamond", age = 43}
ghci> let adRock = Person {firstName = "Adam", lastName = "Horovitz", age = 41}
ghci> let mca = Person {firstName = "Adam", lastName = "Yauch", age = 44}
ghci> mca == adRock
False
ghci> mikeD == adRock
False
ghci> mikeD == mikeD
True
read "Person {firstName =\"Michael\", lastName =\"Diamond\", age = 43}" :: Person
Person {firstName = "Michael", lastName = "Diamond", age = 43}
如果上文没加deriving (Eq, Show),Haskel就报错,说不知道怎么办,没有?。
data Bool = False | True deriving (Ord)
ghci> True `compare` False
GT
ghci> True > False
True
ghci> Nothing < Just 100
True
ghci> Just 3 `compare` Just 2
GT
ghci> Just 100 > Just 50
True
type String = [Char]
type AssocList k v = [(k,v)]
type IntMap v = Map Int v
type IntMap = Map Int
data Either a b = Left a | Right b
多出来的一个参数可以用来报错,?
如我们先前看到的,一个 algebraic data type 的构造子可以有好几个 field,其中每个 field 都必须有具体的型态。因此,我们能定义一个型态,其中他的构造子的 field 的型态是他自己。这样我们可以递归地定义下去,某个型态的值便可能包含同样型态的值,进一步下去他还可以再包含同样型态的值。
infixr 5 :-:
data List a = Empty | a :-: (List a) deriving (Show, Read, Eq, Ord)
ghci> 3 :-: 4 :-: 5 :-: Empty
(:-:) 3 ((:-:) 4 ((:-:) 5 Empty))
data Tree a = EmptyTree | Node a (Tree a) (Tree a) deriving (Show, Read, Eq)
treeElem :: (Ord a) => a -> Tree a -> Bool
treeElem x EmptyTree = False
treeElem x (Node a left right)
| x == a = True
| x < a = treeElem x left
| x > a = treeElem x right
singleton :: a -> Tree a
singleton x = Node x EmptyTree EmptyTree
treeInsert :: (Ord a) => a -> Tree a -> Tree a
treeInsert x EmptyTree = singleton x
treeInsert x (Node a left right)
| x == a = Node x left right
| x < a = Node a (treeInsert x left) right
| x > a = Node a left (treeInsert x right)
singleton函数:一做一个含有两棵空子树的节点的函数4
ghci> let nums = [8,6,4,1,7,3,5]
ghci> let numsTree = foldr treeInsert EmptyTree nums
ghci> numsTree
Node 5 (Node 3 (Node 1 EmptyTree EmptyTree) (Node 4 EmptyTree EmptyTree)) (Node 7 (Node 6 EmptyTree EmptyTree) (Node 8 EmptyTree EmptyTree))
在 foldr 中,treeInsert 是做 folding 操作的函数,而 EmptyTree 是起始的 accumulator,nums 则是要被走遍的 List。
data TrafficLight = Red | Yellow | Green
instance Eq TrafficLight where
Red == Red = True
Green == Green = True
Yellow == Yellow = True
_ == _ = False
instance Eq (Maybe m) where
Just x == Just y = x == y
Nothing == Nothing = True
_ == _ = False
注意到,我们虽然注意到了明确类型Maybe为一个确实值Maybe m,却没有保证这个确定值m属于Eq。为此,修改以下为正确定义:
instance (Eq m) => Eq (Maybe m) where
Just x == Just y = x == y
Nothing == Nothing = True
_ == _ = False
ghci> let nums = [8,6,4,1,7,3,5]
ghci> let numsTree = foldr treeInsert EmptyTree nums
ghci> numsTree
Node 5 (Node 3 (Node 1 EmptyTree EmptyTree) (Node 4 EmptyTree EmptyTree)) (Node 7 (Node 6 EmptyTree EmptyTree) (Node 8 EmptyTree EmptyTree))
在 foldr 中,treeInsert 是做 folding 操作的函数,而 EmptyTree 是起始的 accumulator,nums 则是要被走遍的 List。
在 ghci 中输入 :info Num 会告诉你这个 typeclass 定义了哪些函数,还有哪些类型属于这个 typeclass。
:info 也可以查找类型跟类型构造子的信息。如果你输入 :info Maybe。他会显示 Maybe 所属的所有 typeclass。:info 也能告诉你函数的类型声明。