Haskell 函数
Haskell 函数
函数应用
函数应用于实参: 实参替换右侧表达式的变量(\(\lambda\) 演算 \(\beta\) 归约), 结果是最简表达式或函数调用表达式
函数应用顺序不影响最终结果, 只影响计算步骤数和计算是否终止
函数分类
位置
前缀函数
前缀式调用 ()
10级, 左结合
中缀函数
中缀式调用 ``
默认 infixl 9
[infixl/infixr/infix] [0-9]
优先级: 分组方式(隐式括号)
结合性: 相同优先级时的分组方式
Section
(#) (x #) (# y)
(#) = \x y -> x # y
(x #) = \y -> x # y
(# y) = \x -> x # y
语法
普通函数
Lambda 函数
->
优先级比::
低,\... -> ... :: Type
值构造子
分段函数
模式
f pattern =
f pattern =
..
谓词
f pattern
| predicate =
| predicate =
| otherwise =
函数特性
\(\alpha\) 归约: 换参数名
\(\beta\) 归约: 柯里化
\(\eta\) 归约: point-free style
函数组合 .
infixr 9 .
(.) :: (b -> c) -> (a -> b) -> a -> c
f . g = \x -> f (g x)
柯里化函数
输出函数: 元组式参数拆分为多参数分批输入, 每次返回函数
f :: (a,b) -> c
f :: a -> b -> c
高阶函数
函数作为输入
f :: (a -> b) -> a -> b
递归函数
递归定义
-
定义类型
-
枚举情况
-
定义简单情况
-
定义其他情况
-
泛化和简化
递归分类
单递归参数
f [] =
f (x:xs) = g (f xs)
多递归参数
f [] _ =
f _ [] =
f (x:xs) (y:ys) = g (f xs ys)
多重递归
f 0 =
f 1 =
f n = g $ (f x) (f y)
互递归
f 0 =
f n = g x
g 0 =
g n = f x
递归模式
unfold
参考 Programming in Haskell ch.7.9
unfold :: (a -> Bool) -> (a -> b) -> (a -> a) -> a -> [b]
unfold p h t x | p x = []
| otherwise = h x : unfold p h t (t x)
int2bin = unfold (== 0) (`mod` 2) (`div` 2)
chop8 = unfold null (take 8) (drop 8)
map f = unfold null (f . head) tail
iterate f = unfold (const False) id f
folde
参考 Programming in Haskell ch.8.9
data Expr = Val Int | Add Expr Expr
folde :: (Int -> a) -> (a -> a -> a) -> Expr -> a
folde f g (Val x) = f x
folde f g (Add x y) = g (folde f g x) (folde f g y)
eval :: Expr -> Int
eval = folde id (+)
size :: Expr -> Int
size = folde (const 1) (+)
expr = Add (Add (Val 2) (Val 3)) (Val 4)
Fold
foldr
递归模式
_ [] = v
_ (x:xs) = x # _ xs
抽像出:
-
[] 映射为 v
-
运算符 #, 操作数 x 和 xs 映射结果
-
# 右结合
-
展开对象 _ xs
foldr
抽像上述递归模式为
foldr (#) v xs
迭代思想
v 替换 [], # 替换 :
foldr (#) v [xn, ... , x1] = xn # (... (x1 # v))
递归思想
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f v [] = v
foldr f v (x:xs) = f x (foldr f v xs)
数学思想
对于数列 \(a_1,a_{2}\dots a_n\) 二元函数 \(\#\), 定义 \(f_n(x)\)
数列 \(a_1,a_{2}\dots a_n\) 对应列表 \([a_n,a_{n-1}\dots a_1]\)
展开对象 \(f_i(x)\)
案例
length
length = foldr (\_ b -> 1 + b) 0
v = 0
# = \_ b -> 1 + b
length [] = 0
length (_:xs) = 1 + length xs
reverse
reverse = foldr (\x b -> b ++ [x]) []
v = []
# = \x b -> b ++ [x]
reverse [] = []
reverse (x:xs) = reverse xs ++ [x]
foldl
递归模式
_ v [] = v
_ v (x:xs) = _ (v # x) xs
抽像出:
- [] 映射为参数 v
- 参数 v 与 x 进行 # 运算后带入参数 v
- # 左结合
- 展开对象参数 v
foldl
抽像上述递归模式为
foldl (#) v xs
迭代思想
foldl (#) v [xn, ... , x1] = ((v # xn)...) # x1
递归思想
foldl :: (b -> a -> b) -> b -> [a] -> b
foldl f v [] = v
foldl f v (x:xs) = foldl f (f v x) xs
数学思想
对于数列 \(a_1,a_{2}\dots a_n\) 二元函数 \(\#\), 定义 \(f_n(x)\)
数列 \(a_1,a_{2}\dots a_n\) 对应列表 \([a_n,a_{n-1}\dots a_1]\)
展开对象 \(x\)
案例
length
length = foldl (\b _ -> b + 1) 0
v = 0
# = \b _ -> b + 1
length v [] = v
length v (_:xs) = length (v + 1) xs
reverse
reverse = foldl (:) []
v = []
# = (:)
reverse v [] = v
reverse v (x:xs) = reverse (x:v) xs
重要函数
运算符
operator | 优先级结合性 | 作用 |
---|---|---|
$ | infixr 0 $ |
向左管道 |
& |
infixl 1 & |
向右管道 |
. |
infixr 9 . |
函数组合 |
: |
infixr 5 : |
前插 List |
++ |
infixr 5 ++ |
List 拼接 |
!! |
infixl 9 !! |
取数 |
<$> |
infixl 4 <$> |
中缀 fmap |
<*> |
infixl 4 <*> |
context 值相互作用 |
>>= |
infixl 1 >>= |
单子函数维护 context |
<=< |
infixr 1 <=< |
单子函数组合 |
map 映射
map
将函数 a -> b
映射为函数 [a] -> [b]
map
是对 []
并行处理的抽像:
map
并不关心函数 a -> b
作用的先后顺序, 可以从最后一个元素算起, 也可以从中间任意一个位置算起, 甚至可以将计算分成若干份交给 GPU 并行计算, 只要保证源 List与结果 List的元素一一对应
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
filter 过滤
过滤出满足 predicate 的所有元素
filter :: (a -> Bool) -> [a] -> [a]
filter _ [] = []
filter p (x:xs)
| p x = x : filter p xs
| otherwise = filter p xs
fold 折叠
将 List 聚合为一个值
折叠是顺序递归操作的抽像
fold f acc list
- 聚合函数 f
- 初值(累加值) acc
foldl
从左到右, 初值在左, 不能处理无限 List
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
foldl _ acc [] = acc
foldl f acc (x:xs) = foldl f (f acc x) xs
foldl + 0 [1, 2, 3]
foldl + (+ 0 1) [2, 3]
foldl + (+ (+ 0 1) 2) [3]
foldl + (+ (+ (+ 0 1) 2) 3) []
+ (+ (+ 0 1) 2) 3
(+ (+ 0 1) 2) + 3
((+ 0 1) + 2) + 3
((0 + 1) + 2) + 3
foldr
从右到左, 初值在右, 能处理无限 List
fodlr :: Foldable t => (a -> b -> b) -> b -> t a -> b
fold _ acc [] = acc
fold f acc (x:xs) = f x (foldr f acc xs)
foldr + 0 [1, 2, 3]
+ 1 (foldr + 0 [2, 3])
+ 1 (+ 2 (foldr + 0 [3]))
+ 1 (+ 2 (+ 3 (foldr + 0 [])))
+ 1 (+ 2 (+ 3 0))
+ 1 (+ 2 (3 + 0))
+ 1 (2 + (3 + 0))
1 + (2 + (3 + 0))
map f = foldr ((:) . f) []
foldl 由 foldr 实现
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
foldl f accc xs = foldr (\acc g x -> g (f x acc)) id xs accc
foldl1
与 foldr1
首尾元素为初值
scan
scanl scanl1 scanr scanr1 记录累加值的所有状态(包括初值)到 list
zip
打包
zip :: [a] -> [b] -> [(a, b)]
zip [] _ = []
zip _ [] = []
zip (x:xs) (y:ys) = (x, y) : zip xs ys
zipWith
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith _ [] _ = []
zipWith _ _ [] = []
zipWith f (x:xs) (y:ys) = f x y : zipWith' f xs ys
flip
调换参数位置
flip :: (a->b->c) -> b -> a -> c
flip f y x = f x y
General 函数
id
id :: a -> a
id x = x
const
const :: a -> b -> a
const x _ = x
not
not :: Bool -> Bool
not True = False
not False = True
otherwise
otherwise :: Bool
otherwise = True
fst
fst :: (a, b) -> a
fst (x, _) = x
snd
snd :: (a, b) -> b
snd (_, y) = y
++
(++) :: [a] -> [a] -> [a]
(++) (x:xs) ys = x : xs ++ ys
!!
(!!) :: [a] -> Int -> a
xs !! n | n < 0 = error
[] !! _ = error
(_:xs) !! n = xs !! (n-1)
head
head :: [a] -> a
head (x:_) = x
head [] = error
tail
tail :: [a] -> [a]
tail (_:xs) = xs
tail [] = error
min
min :: Ord a => a -> a -> a
min x y = if x <= y then x else y
max
max :: Ord a => a -> a -> a
max x y = if x <= y then y else x
curry
curry :: ((a, b) -> c) -> a -> b -> c
curry f x y = f (x, y)
uncurry
uncurry :: (a -> b -> c) -> (a, b) -> c
uncurry f (x, y) = f x y
fromEnum
fromEnum :: Enum a => a -> Int
toEnum
toEnum :: Enum a => Int -> a
\(~\)
函数库
常用
Num
fromIntegral | 整数换为通用数 |
---|
List
data List a = [] | a : List a
取元素
!! | 第 i 个元素 |
---|---|
take | 前n个元素 |
head | 头部 |
tail | 尾部 |
last | 尾元素 |
init | 非尾 |
maximum | 最大元素 |
minimum | 最小元素 |
计算
length | 长度 |
---|---|
null | 判空 |
elem | 判存 \(a\in A\) |
notElem | 判存 \(a\not\in A\) |
sum | 元素和 |
product | 元素积 |
and | 全部与 |
or | 全部或 |
变换
: | 前插 |
---|---|
++ | 合并, 遍历左 List |
reverse | 反转 |
drop | 删除前 n 个元素 |
List 生成
cycle | 重复 List |
---|---|
repeat | 重复元素 |
replicate | 重复元素 n 次 |
zip | 生成 pair list |
zipWith | 二元函数 zip |
List comprehension
[expr | x <- generator, ...]
次序靠后的生成器嵌套更深, 因而次序靠后的分量变化更频繁
IO
IO action 绑定到 main 时触发
putStrLn :: String -> IO ()
putStr :: String -> IO () 边界条件为空字串
putChar :: Char -> IO ()
print :: Show a => a -> IO ()
getChar :: IO Char
由于缓冲区, 只有按下 Enter 时才会触发读取字符的行为
when :: Applicative f => Bool -> f () -> f () 封装 if something then do some I/O action else return ()
sequence :: [IO a] -> IO [a] [a] IO action 返回值的 List
rs <- sequence [getLine, getLine, getLine]
mapM mapM_ mapM map 后 sequence, mapM_ map 后 sequence 并丢弃结果
forever 无限循环 IO action
forM
文件
getContents :: IO String 行读入, 读到 EOF, Lazy IO
interact :: (String -> String) -> IO ()
openFile :: FilePath -> IOMode -> IO Handle
type FilePath = String
data IOMode = ReadMode | WriteMode | AppendMode | ReadWriteMode
hGetContents :: Handle -> IO String
hClose :: Handle -> IO ()
withFile :: FilePath -> IOMode -> (Handle -> IO a) -> IO a
hGetLine、hPutStr、hPutStrLn、hGetChar
readFile :: FilePath -> IO String
writefile :: FilePath -> String -> IO ()
appendFile :: FilePath -> String -> IO ()
默认情况下:
文本文件 line-buffering
二进制文件 block-buffering
hSetBuffering :: Handle -> BufferMode -> IO () 设置 buffer 模式
data BufferMode = NoBuffering | LineBuffering | BlockBuffering (Maybe Int)
- NoBuffering: char
- LineBuffering: line
- BlockBuffering: Nothing(操作系统) Just Int byte
hFlush :: Handle -> IO ()
openTempFile :: FilePath -> String -> IO (FilePath, Handle)
removeFile :: FilePath -> IO ()
renameFile :: String -> FilePath -> IO ()
System.Environment
getArgs :: IO [String] 获取命令行参数
getProgName :: IO String 获取程序名称
字节流
单位 byte(8 bit)
Strict bytestring
- Data.ByteString
- 无惰性
- 一次性计算整个 bytestring
Lazy bytestring
- Data.ByteString.Lazy
- 惰性
- 每 chunk 读
pack :: [Word8] -> ByteString
unpack :: ByteString -> [Word8]
fromChunks strict bytestring 转 lazy bytestring
toChunks lazy bytestring 转 strict bytestring
empty 空 bytestring
Exception
- pure code 和 IO code 都能抛出 Exception
- 只有 IO code 才能接收 Exception
System.Directory
doesFileExist :: FilePath -> IO Bool
System.IO.Error
catch :: IO a -> (IOError -> IO a) -> IO a
- IO a try block
- (IOError -> IO a) catch block
isDoesNotExistError :: IOError -> Bool
ioError :: IOException -> IO a
Bounded
minBound maxBound
模块函数
Data.List
intersperse item 穿插 []
intercalate [] 穿插 [[]] 后 []
transpose 翻转二维 List (矩阵)
fold' 和 foldl1' 非惰性实现, 防止堆栈溢出
concat 移除 List 一层嵌套
concatMap map List 后再 concat
and 整个 List 与
or 整个 List 或
any all 检查 List 每个/某个元素是否符合 f 函数
iterate 一直调用函数, 产生无限 List
splitAt List 在特定位置断开, 返回二元组List
takeWhile 从 List 取元素, 直到 False
dropWhile 扔掉符合条件的元素, 直到 False, 返回剩余部分
span 首次 False 断开, 返回两个 List True 部分和 False 部分
break 首次 True 断开, 返回两个 List
sort
group 对 List 连续且相等元素分段
inits 和 tails 与 init
tail
相似但会递归地调用自身直到为空
isInfixOf 是否包含子集合
isPrefixOf 与 isSuffixOf 是否以某子集合开头或结尾
elem 与 notElem 是否包含某元素
partition 限制函数 limit 对 List 划分, 一个 List True 元素, 一个 List False 元素
find 返回首个符合条件的Maybe
元素
elemIndex 返回元素Maybe
索引
elemIndices 返回元素索引 List
findIndex 返回所有符合条件元素 List
zip3 ... zip7 和 zipWith3 ... zipWith7
lines 返回 String 的所有行, List
unlines lines
的反函数
words 和 unwords 把 String 分为一组单词和反操作
nub 去除 List 重复元素
delete 删除首次出现的某元素
\ 差集操作 \(A - B\)
union 并集 \(A\bigcup B\)
intersect 交集 \(A \bigcap B\)
insert 将元素插入首个大于等于的元素前
setNub 不保留原有顺序, 但速度比 num
快
genericLength genericTake genericDrop genericSplitAt genericIndex genericReplicate 返回值为 Num
nubBy deleteBy unionBy intersectBy groupBy 用函数判定相等性而不是 ==
on
on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
f `on` g = \x y -> f (g x) (g y)
ghci> groupBy ((==) `on` (> 0)) values
[[-4.3,-2.4,-1.2],[0.4,2.3,5.9,10.5,29.1,5.3],[-2.4,-14.5],[2.9,2.3]]
sortBy insertBy maximumBy minimumBy
Data.Char
isControl 控制字符
isSpace 空白符
isLower 小写
isUper 大写
isAlpha 字母
isAlphaNum 字母或数字
isPrint 可打印
isDigit 数字
isOctDigit 八进制数字
isHexDigit 十六进制数字
isLetter 字母
isMark 注音字符
isNumber 数字
isPunctuation 标点符号
isSymbol 货币符号
isSeperater 空格或分隔符
isAscii unicode 前128
isLatin1 unicode 前 256
isAsciiUpper 大写 ascii
isAsciiLower 小写 ascii
GeneralCategory 类型(枚举)
toUpper 大写
toLower 小写
toTitle title-case
digitToInt char -> int
intToDigit int -> char
ord char char <-> num
Data.Map
import qualified Data.Map as Map
lookup key -> Maybe value
fromList List -> Map
empty 空 map
insert 插入入新 k-v
null 是否空
size 大小
singleton 一个 k-v 的 map
lookup
member 是否有 k
map filter f 对 v 作用
toList fromList
的反函数
keys elems keys values
fromListWith f 对重复 key 的 values 处理, 默认放在 List 中
insertWith 处理已存在 k 的 value
Data.Set
import qualified Data.Set as Set
fromList List -> Set
difference \(A - A \bigcap B\)
union \(A \bigcap B\)
null size member empty singleton insert delete
isSubsetOf isProperSubsetOf 子集 真子集
map filter
toList Set->List
System.Random
random :: (RandomGen g, Random a) => g -> (a, g)
- RandomGen 随机数生成
- StdGen
- Random 随机数值
mkStdGen :: Int -> StdGen
random (mkStdGen 100) :: (Int, StdGen)
randoms
randomR :: (RandomGen g, Random a) :: (a, a) -> g -> (a, g)
randomRs
getStdGen
newStdGen