「Learn Haskell」#1 基础语法与函数
基础运算
+ - * / ()
:加减乘除div
:整除mod
:取模True False
:布尔值|| && not
:或且非==
:条件判断,相等/=
:条件判断,不等
函数调用
Haskell中调用函数不加括号,先写出函数名,然后逐个列出参数,用空格隔开:
1 | ghci> max 1 2 |
前缀(prefix)函数与中缀(infix)函数转换:
- 对前缀函数加
``
使其变成中缀函数 - 对中缀函数加
()
使其变成前缀函数
1 | ghci> 4 `div` 2 |
List
列表是Haskell中很常见的数据类型,和Python中不同,Haskell中的列表中的所有元素必须是同一个类型。
以下是列表常用的函数:
(++)
:: [a] -> [a] -> [a]:合并两个列表(:)
:: a -> [a] -> [a]:将单个元素并入列表。[1, 2, 3]是1:2:3:[]的语法糖(!!)
:: [a] -> Int -> a:通过索引取出某个位置上的元素。a !! 1相当于Python中的a[1]head
:: [a] -> a:返回列表的第一个元素tail
:: [a] -> [a]:返回列表中除去第一个元素后的列表(若只有一个元素则返回空列表[])last
:: [a] -> a:返回列表中的最后一个元素init
:: [a] -> [a]:返回列表中除去最后一个元素后的列表length
:: Foldable t => t a -> Int:返回列表的长度null
:: Foldable t => t a -> Bool:返回列表是否为空reverse
:: [a] -> [a]:返回翻转后的列表take
:: Int -> [a] -> [a]:返回列表a的前n个元素的列表(take n a)drop
:: Int -> [a] -> [a]:返回列表a中除去前n个元素后的列表(drop n a)maximum
:: (Foldable t, Ord a) => t a -> a:返回列表中的最大值minimum
:: (Foldable t, Ord a) => t a -> a:返回列表中的最小值sum
:: (Foldable t, Num a) => t a -> a:返回列表中所有元素的和product
:: (Foldable t, Num a) => t a -> a:返回列表中所有元素的积elem
:: (Foldable t, Eq a) => t a -> Bool:判断值n是否在列表a中(1
2
3elem n a
-- 或
n `elem` a --用``包上可以变成中缀函数使用
Texas ranges
使用..
可以表示出范围并自动推导:
1 | ghci> [1 .. 10] |
也可以用来生成无穷列表,如[1..]、[1, 3..]。同时也有函数可以生成无穷列表:
cycle
:: [a] -> [a]:将原列表不断循环生成无穷列表repeat
:: a -> [a]:将传入的值不断重复生成无穷列表replicate
:: Int -> a -> [a]:将值a重复n次,返回生成的列表(replicate n a)
List comprehension
Haskell中也有列表推导,形式是一个中括号,左侧为表达式,右侧为变量的范围和约束条件
1 | ghci> [x * 2 | x <- [1 .. 10]] |
Tuple
Haskell中的元组可以有不同长度,元素可以有不同类型。并且一个元组的类型由其中所有元素的类型共同决定。它的常用函数:
fst
:: (a, b) -> a:返回含有两个元素元组中的第一个元素snd
:: (a, b) -> b:返回含有两个元素元组中的第二个元素zip
:: [a] -> [b] -> [(a, b)]:接收两个列表,返回一个列表,每个元素是依次将两个列表中元素配对成的二元组
Syntax in Functions
函数可以直接定义:
1 | plus x y = x + y |
这时Haskell会自动推断函数的类型为(Num a) => a -> a -> a。但是最好在定义函数前声明函数的类型:
1 | plus :: (Num a) => a -> a -> a |
Pattern matching
定义函数时可以使用模式匹配语法。运行时依次将输入与给出的模式相匹配,如果匹配,就执行对应操作;不匹配,就继续与下一个模式相匹配,直到匹配成功,也因此,最后必须要给出一种通用的匹配来接收与给出模式全不匹配的输入。如:
1 | factorial :: (Integral a) => a -> a |
1 | first :: (a, b, c) -> a |
其中_
表示任何值,且不关心它的内容,只是用来占位
列表的(:)操作也可以用来进行模式匹配:
1 | head' :: [a] -> a |
但(++)操作不可以用来模式匹配
在针对列表进行模式匹配时,如果同时需要整个列表、列表的第一个值、列表除第一个值外的内容,可以使用xs@(q:qs)
。比如[1, 2, 3]通过xs@(q:qs)
匹配后,xs为[1, 2, 3],q为1,qs为[2, 3]
Guard syntax
在函数的定义中,也可以使用守卫(guard)语法:
1 | max' :: (Ord a) => a -> a -> a |
先给出传入的参数变量,然后下一行缩进后加|,|后面等号前表示进行的判断,如果为True则返回这个等号后面的值;如果为False则继续判断下一行,直到otherwise
Case expressions
在函数的定义中,也可以使用case表达式来配合模式匹配使用:
1 | case expression of pattern -> result |
例如:
1 | head' :: [a] -> a |
1 | describeList :: [a] -> String |
where
声明在函数定义中要使用的局部变量,可以使用where关键字:
1 | initials :: String -> String -> String |
在where中,也可以使用上面的模式匹配
let
let <bindings> in <expression>
语法可以在函数的定义中使用,也可以在普通算式或列表中使用:
1 | cylinder :: (RealFloat a) => a -> a -> a |
1 | ghci> 4 * (let a = 9 in a + 1) + 2 |
if statement
Haskell中的if语句为:
1 | if ... then ... |
其中最后一个else无论如何也不可以省去
Reference
目录
#0 | 总章
#1 | 基础语法与函数
#2 | 高阶函数与模块
#3 | 类型与类型类
#4 | 输入输出与文件
#5 | 函子、应用函子与单子
#6 | 半群与幺半群
#7 | 一些其它类型类
#A | Haskell与范畴论
「Learn Haskell」#1 基础语法与函数