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

递归函数

递归定义

  1. 定义类型

  2. 枚举情况

  3. 定义简单情况

  4. 定义其他情况

  5. 泛化和简化

递归分类

单递归参数

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]\)

\[\begin{array}{lcl} f_0(x) &= &x\\ f_1(x) &= &a_1\ \#\ f_0(x)\\ f_2(x) &= &a_2\ \#\ f_1(x)\\ &\dots&\\ f_{n}(x) &= &a_n\ \#\ f_{n-1}(x)\\ \end{array} \]

展开对象 \(f_i(x)\)

\[f_{n}(v) = a_n\ \#\ a_{n-1}\ \#\ \dots \ a_1\ \#\ v \]

案例

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]\)

\[\begin{array}{lcl} f_0(x) &= &x\\ f_1(x) &= &f_0(x\ \#\ a_1)\\ f_2(x) &= &f_1(x\ \#\ a_2)\\ &\dots&\\ f_{n}(x) &= &f_{n-1}(x\ \#\ a_n)\\ \end{array} \]

展开对象 \(x\)

\[f_{n}(v) = v\ \#\ a_n\ \#\ a_{n-1}\ \#\ \dots\ a_1 \]

案例

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

foldl1foldr1 首尾元素为初值

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

hGetLinehPutStrhPutStrLnhGetChar

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 连续且相等元素分段

initstailsinit tail 相似但会递归地调用自身直到为空

isInfixOf 是否包含子集合

isPrefixOfisSuffixOf 是否以某子集合开头或结尾

elemnotElem 是否包含某元素

partition 限制函数 limit 对 List 划分, 一个 List True 元素, 一个 List False 元素

find 返回首个符合条件的Maybe元素

elemIndex 返回元素Maybe索引

elemIndices 返回元素索引 List

findIndex 返回所有符合条件元素 List

zip3 ... zip7zipWith3 ... zipWith7

lines 返回 String 的所有行, List

unlines lines 的反函数

wordsunwords 把 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

posted @ 2025-04-09 22:30  (.)$(.)  阅读(17)  评论(0)    收藏  举报