In [1]:
-- haskell支持模式匹配,类似erlang. 不如说erlang类似haskell
lucky :: Int -> String
lucky 7 = "Lucky Number server!"
lucky x = "Sorry, you're out of luck. pal!"
In [2]:
-- 一般需要写一个万能匹配模式.
sayMe :: Int -> String
sayMe 1 = "One!"
sayMe 2 = "Two!"
sayMe 3 = "Trhee!"
sayMe 4 = "Four!"
sayMe 5 = "Five!"
sayMe x = "Not Between 1 and 5"
In [3]:
-- 阶乘函数,使用递归定义函数
factorial :: Int -> Int
factorial 0 = 1
factorial n = n * factorial (n -1)
In [8]:
charName :: Char -> String
charName 'a' = "Albert"
charName 'b' = "Broseph"
charName 'c' = "Cecil"
In [5]:
charName 'a'
In [6]:
charName 'b'
In [9]:
charName 'c'
In [10]:
-- this would raise
-- charname 'h'
In [12]:
-- 对tuple使用模式匹配
addVectors :: (Double, Double) -> (Double, Double) -> (Double, Double)
addVectors (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)
In [13]:
:t addVectors
In [14]:
first :: (a, b, c) -> a
first (x, _, _) = x
In [16]:
second :: (a, b, c) -> b
second (_, x, _) = x
In [17]:
third :: (a, b, c) -> c
third (_, _, x) = x
In [18]:
-- 对list使用模式匹配
-- 列表推导中如果匹配失败会continue到下一个元素
let xs = [(1, 3), (4, 3), (2,4), (5,3), (5,6), (3,1)]
[a+b | (a,b) <- xs]
In [20]:
head':: [a] -> a
head' [] = error "cannot call on empty list"
-- 绑定多个变量需要用 `()`,不然无法识别
head' (x:_) = x
In [21]:
head' [4, 5, 6]
In [22]:
head' "hello"
In [24]:
tell :: (Show a) => [a] -> String
tell [] = "empty"
tell (x:[]) = "one item"
tell (x:y:[]) = "two item"
tell (x:y:z:[]) = "three item"
In [25]:
tell [1]
In [26]:
tell [True, False]
In [27]:
tell []
In [28]:
-- 列表模式匹配中无法私用 ++, 因为无法判断两边长度
In [31]:
-- as 模式.用来在模式匹配中保留对整体值的引用
firstletter :: String -> String
firstletter "" = "Empty strings."
firstletter all@(x:xs) = "first: " ++ [x] ++ ".all: " ++ all
firstletter "hell world"
In [ ]:
-- 哨兵. 第一个哨兵和函数参数之间没有 `=`
-- 模式用来检查参数结构。哨兵可以进一步检查参数性质
-- 注意 | 要求对齐,不然无法识别. | 要缩进四个空格
-- otherwise 作为万能条件. 类似case.default
bmiTell :: Double -> String
bmiTell bmi
| bmi <= 18.5 = "you'are thin"
| bmi <= 25.0 = "you'are normal"
| bmi <= 30.0 = "you are fat"
| otherwise = "you are whalt"
In [34]:
-- 多参数哨兵
bmiTell :: Double -> Double -> String
bmiTell weight height
| weight / height ^ 2 <= 18.5 = "you are thin"
| weight / height ^ 2 <= 25.0 = "you are nomral"
| weight / height ^ 2 <= 30.0 = "you are fat"
| otherwise = "youare whalt"
bmiTell 85 1.90
In [35]:
max' :: (Ord a) => a -> a -> a
max' a b
| a < b = b
| otherwise = a
In [36]:
-- 使用``直接定义中缀函数
myCompare :: (Ord a) => a -> a -> Ordering
a `myCompare` b
| a == b = EQ
| a > b = GT
| a < b = LT
In [38]:
-- 函数之后使用where绑定名字(类似常量)
-- 只能在当前模式下使用.用来保存中间结果
bmiTell :: Double -> Double -> String
bmiTell weight height
| weight / height ^ 2 <= 18.5 = "thin"
| weight / height ^ 2 <= 25.0 = "normal"
| weight / height ^ 2 <= 30.0 = "fat"
| otherwise = "whalt"
In [40]:
-- 使用where避免重复计算
bmiTell :: Double -> Double -> String
bmiTell weight height
| bmi <= 18.5 = "thine"
| bmi <= 25.0 = "normal"
| bmi <= 30.0 = "fat"
| otherwise = "whalt"
where bmi = weight / height ^ 2
In [42]:
-- take where go farward
-- where绑定多个常量需要保持对齐`
bmiTell :: Double -> Double -> String
bmiTell weight height
| bmi <= thin = "thin"
| bmi <= normal = "normal"
| bmi <= fat = "fat"
| otherwise = "whalt"
where bmi = weight / height ^ 2
thin = 18.5
normal = 25.0
fat = 39.0
In [43]:
-- where只再本模式可用,要跨多个模式需要使用全局定义
badGreeting :: String
badGreeting = "it is you"
niceGreeting :: String
niceGreeting = "nice to see you"
greet :: String -> String
greet "Juan" = niceGreeting ++ "Juan"
greet "Fern" = niceGreeting ++ "Fern"
greet name = badGreeting ++ name
In [44]:
-- where中也可以使用模式匹配
bmiTell weight height
| bmi <= thin = "thin"
| bmi <= normal = "normal"
| bmi <= fat = "fat"
| otherwise = "whalt"
where bmi = weight / height ^ 2
(thin, normal, fat) = (18.5, 25.0, 30.0)
In [45]:
initial :: String -> String -> String
initial firstname lastname = [f] ++ ". " ++ [l] ++ "."
where (f:_) = firstname
(l:_) = lastname
In [46]:
-- 可以在where中定义函数
calBmis :: [(Double, Double)] -> [Double]
calBmis xs = [bmi w h | (w, h) <- xs]
where bmi weight height = weight / height ^ 2
In [48]:
-- let 用于绑定定义.
-- 单独let只能在ghci中使用.
-- let...in.., 定义只在in中有效
-- let是个表达式,会返回值,可以在所有地方使用,不像where
cylinder :: Double -> Double -> Double
cylinder r h =
let sideArea = 2 * pi * r * h
topArea = pi * r ^ 2
in sideArea + 2 * topArea
cylinder 10.0 20
In [50]:
4 * (let a = 9 in a + 1) + 2
In [51]:
-- let常用
-- 在局部作用与定义函数
[let square x = x * x in (square 5, square 3, square 2)]
In [52]:
-- 绑定多个定义需要使用 ;
(let a = 100; b = 200; c = 300 in a*b*c, let foo="hey";bar="there" in foo ++ bar)
In [53]:
-- 从tuple中解item
(let (a,b,c) = (1,2,3) in a+b+c)* 100
In [55]:
-- 在列表推导中使用let
calBmis :: [(Double, Double)] -> [Double]
calBmis xs = [bmi | (w, h) <- xs, let bmi = w /h * 2]
In [56]:
-- case表达式,类似swtich, 是一个表达式可用在任何地方
-- 模式匹配是case的语法糖
head' :: [a] -> a
head' xs = case xs of [] -> error "not empty me"
(x:_) -> x
In [57]:
desc :: [a] -> String
desc ls = "list is " ++ case ls of [] -> "empty"
[x] -> "signle"
xs -> "longer list"
In [58]:
desc' :: [a] -> String
desc' ls = "list is " ++ what ls
where what [] = "empty"
what [x] = "single"
what xs = "longger list"