haskell 学习
haskell笔记
基础
变量
变量命名使用驼峰式
函数
调用
先写函数名后加参数,如min 1 2
声明
先函数名,后跟空格分隔的参数表,然后加=后定义函数行为
doubleme x = x+x
常用函数
replicate n m 复制n个m
if语句
1 | doubleme x = if x>100 |
if里 else部分不能省略
if语句是一个表达式,即返回一个值的代码。
变量
在ghci下使用let或在脚本中直接写a=1定义
List
[_x]匹配只有一个元素时的元素
let a = [1,2,3,4]
记得用逗号隔开
字符串就是字符的list
- 合并list:
[1,2,3] ++ [4,5,6]
"hello" ++ "world"
合并时会遍历整个list,长字符串性能差
- 前插元素:
1:[2,3,4,5]
++操作需要两个操作数都是list,因此需要[1] ++ [2]
:操作是将一个字符前插到一个list,因此[1,2,3]
实质上就是1:2:3:[]
- 索引元素:
[1,2,3,4] !! 1
,[[[],[]],[]] !! 0 !! 1
- Head 获取第一个元素
- tail 获取除去第一个剩下的
- last 获取最后一个
- init 获取除去最后一个剩下的
- length 获取长度
- null 获取是否为空
- Reverse 反转列表
- take n list 获取前n个元素
take 10 (repeat 5)
replicate 3 10
- drop n list 删除前n个元素
- n elem list 判断n是否在list里
Range
[1..20]
[1,2..20]
只会按照特定加法步长生成list,不要使用浮点数
可以定义无限长度list,如取前24个3的倍数。take 24 [3,6..]
由于Haskell是懒惰的,所以他只会在你取值的时候进行计算。
元组Tuple
用小括号定义
与list区别:可以存入多种元素,可以包含多种类别的元素
zip函数接受两个list,生成一个包含tuple的list。若长短不一则长的适配短的
1 | ghci> zip [1,2,3,4,5] [5,5,5,5,5] |
函数语法
模式匹配
模式匹配通过检查数据的特定结构来检查其是否匹配,并按模式从中取得数据。
1 | sayMe :: (Integral a) => a -> String |
若想匹配不需要的东西就需要用括号括起来并且用_表示
递归常使用(x:xs)进行匹配
1 | sum' :: (Num a) => [a] -> a |
as模式:
将一个名字和 @
置于模式前,可以在按模式分割什么东西时仍保留对其整体的引用。
1 | capital :: String -> String |
Guards
用来检查一个值的某项属性是否为真
1 | bmiTell :: (RealFloat a) => a -> String |
竖线就是guards,若为真就使用,为假就往下
Where
写在guards下边
1 | bmiTell :: (RealFloat a) => a -> a -> String |
let
let必须跟一个in,在let里定义的变量可以在in里当成私有变量来使用。
1 | cylinder :: (RealFloat a) => a -> a -> a |
let是一个表达式,可以在任何地方使用。
1 | ghci> (let (a,b,c) = (1,2,3) in a+b+c) * 100 |
case
Case 类似switch
1 | case expression of pattern -> result |
1 | head' :: [a] -> a |
常用函数
zip [a] [b]
返回数组,将a,b组合起来,若长度不同则以短的为准
replicate a b
返回数组,把b重复a次
flip f a b
返回f b a的结果
div a b
返回a/b , 只能用于整数
zipWith f [a] [b]
返回数组,每一项是a,b中相应项经过f操作后的结果
map f [a]
返回数组,每一项是a经过f操作后的结果
filter (a->bool) [a]
返回数组,a数组经过限制条件后剩余元素
takeWhile (a->bool) [a]
返回符合限制条件的元素数组
dropWhile (a->bool) [a]
返回去除条件后的数组
odd
判断是不是基数
even
判断是不是偶数
words
把string中的单词拆出来成为数组
unwords
把单词数组组合成String
计算函数
mod 取模
div 除
自定义type
继承类
show
让他可以print
Eq
可以做比较
输入输出
输入
putStrLn
Functor,Applicative Functor,Monoids
Functor
Functors 是可以被 map over 的对象,这个typeclass只有一个method是fmap
fmap
fmap :: (a -> b) -> f a -> f b
提供一个函数和一个有盒子的值,输出装着新值的盒子
将输入的方程应用到a上,即 fmap f a = f a
Applicative Functor
pure a = a
1 | (<*>) :: Applicative f => f (a -> b) -> f a -> f b |
提供一个在盒子里的函数和一个盒子里的值,输出装着新值的盒子
1 | ghci> pure (+) <*> Just 3 <*> Just 5 |
1 | (<$>) :: (Functor f) => (a -> b) -> f a -> f b |
1 | ghci> (++) <$> Just "johntra" <*> Just "volta" |
举例:
1 | ghci> a = [(*)]<*>[1,2] |
Monads
bind >>=
1 | (>>=) :: Monad m => m a -> (a -> m b) -> m b |
Laws:
- return v>>=f => f v
- M >>= (= a) => M
pure
Do statement
1 | do |
见到左箭头可以认为从右侧取一个值
x<- m a
通过左箭头后x变成a类型
ghci命令
:l 装载某个hs文件
:l aaa.hs
:t 查看类型
:t 'a'
quickcheck
查看用当前arbitry生成的样本数据
1 | sample' arbitrary :: IO [UpperCaseString] |
使用erlang的quickCheck需要导入包
1 | -include_lib("eqc/include/eqc.hrl"). |
查看eqc生成的样本数据
1 | eqc_gen:sample(dict_eqc:dict_5()). |
Otp
分离发信息和逻辑部分
使用gen_server
cast-> request
Call -> request_reply
handle_cast -> handle_request
Statefunction mode
-behavior(gen_statem)
需要先明确程序的多个状态
lamp module implementation
- module定义,public API定义,callbacks
- start函数,使用gen_statem的start方法,第一个参数是自身module
- button函数,使用cast方法,参数是Lamp和button
- stop函数,使用stop方法
- callback方法:
- 定义init,返回一个三元组
- 定义callback_mode返回state_functions,还可以使用handle_event_functions
- states方法:
- Off接受cast,button,Data,返回四元组{next_state,low-UNSTABLE,Data,2000}
- Low_unstable同样接受三个参数,如果第一个是cast则在触发cast的时候进入,再定义一个第一个是timeout,第二个是_的来等到超时进入。
- 使用:
- {ok,L} = Lamp:start()
supervisor
如果有另一个进程需要执行但是不知道需要执行多久,就spown一个新的,并且用一个supervisor来监督他的执行
理想状况是除了root每个进程都有一个supervisor
Lamp module supervisior implementation
- module定义,export start_link, spawn_lamp
- Export init
- Behaviour 是supervisor
- startlink函数,同上start
- spawnlamp函数,传入一个S,使用supervisior的start_child方法传入两个参数
- init函数,定义一个Child变量,包含一系列参数的tuple。定义RestartStrategy变量,定义了重启时需要的操作。定义MaxRestart变量和MaxTime变量,返回这些变量。
- 在lamp.erl文件中新增一个start_link函数,使用的是他自己behavior的方法
- 使用:
- {ok,S} = lamp_sup:start_link()
- {ok,L1} = Spawn_lamp(S)
- 现在可以使用L1了
- Exit(S,shutdown)关闭supervisor和他下边的所有进程