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'


"Albert"

In [6]:
charName 'b'


"Broseph"

In [9]:
charName 'c'


"Cecil"

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


addVectors :: (Double, Double) -> (Double, Double) -> (Double, Double)

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]


[4,7,6,8,11,4]

In [20]:
head':: [a] -> a
head' [] = error "cannot call on empty list"
-- 绑定多个变量需要用 `()`,不然无法识别
head' (x:_) = x

In [21]:
head' [4, 5, 6]


4

In [22]:
head' "hello"


'h'

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]


"one item"

In [26]:
tell [True, False]


"two item"

In [27]:
tell []


"empty"

In [28]:
-- 列表模式匹配中无法私用 ++, 因为无法判断两边长度

In [31]:
-- as 模式.用来在模式匹配中保留对整体值的引用
firstletter :: String -> String
firstletter "" = "Empty strings."
firstletter all@(x:xs) = "first: " ++ [x] ++ ".all: " ++ all
firstletter "hell world"


"first: h.all: 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


"you are nomral"

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


1884.9555921538758

In [50]:
4 * (let a = 9 in a + 1) + 2


42

In [51]:
-- let常用
-- 在局部作用与定义函数
[let square x = x * x in (square 5, square 3, square 2)]


[(25,9,4)]

In [52]:
-- 绑定多个定义需要使用 ;
(let a = 100; b = 200; c = 300 in a*b*c, let foo="hey";bar="there" in foo ++ bar)


(6000000,"heythere")

In [53]:
-- 从tuple中解item
(let (a,b,c) = (1,2,3) in a+b+c)* 100


600

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"