haskell基本语法
语法入门
haskell作为一个实验性强于实践性的语言,有很多基础语法与传统的c系差异巨大,以往的知识,除了算法,难以直接代入,基本上就是要完全重新开始学.
本文主要面向对c,cpp等命令式编程语言熟悉的读者,主要的内容在于一些思维陷阱和新颖语法的记录,对于haskell中非常基础并且和其他语言相似的部分不会着墨.
关于教材与参考:
不要在入门的时候再看什么中文教材了,尤其是《Haskell函数式编程入门》这种教材.它具有典型的缺陷,比如一次性引入过多新知识而没有完整解释,包含大量与程序无关的冗长内容,对某些可能已经更改的语法细节过度纠结,缺乏渐进的示例,语言表述不准确,甚至有些内容显得玄妙或晦涩.这种教材更适合作为字典使用,而不是入门教材.
推荐 learn you a haskell.这个教材简明易懂,作为入门来说非常适合,英语也比较平白无华,属于说人话而不怎么说废话的教材.更好的是在线版本免费
haskell可以下载安装后使用vscode作为ide, 常见解释器ghci 即 glasgow haskell compiler iterative, 便于入门学习
基本常识
不等于用/=
来表示
Haskell中用空格来表示参数直接的间隔,不需要,
比如1
add 1 2
如果你看到类似 bar (bar 3)
的表达式,它并不是将 bar
和 3
作为参数传递给 bar
,而是先用 3
调用函数 bar
,得到一个结果,然后再用这个结果调用一次 bar
.在C语言中,类似于 bar(bar(3))
.
Haskell中的函数定义不依赖于文本顺序.这个意味着在程序文本中随意调换不同函数的顺序不会有什么影响.
函数名称以小写字母开头,类型名称以大写字母开头.这个并不只是约定俗成的传统,而是系统强制的要求
haskell中没有常见意义里的循环遍历,而是采用函数的方式处理,基础语法中暂不涉及,放在后面函数部分中
if-else
具体格式为1
if condition then action1 else action2
else
是强制要求的.
列表
在haskell中数组的本质:语法糖,对列表的简写,下面的写法是完全等价的
$[a_1,a_i,a_n] == a_1:a_i:a_n:[] == a_1:a_i:a_n$
其中x:xs
代表元素x
连接列表xs
,[]
代表空集
由于列表本质是同类元素连接的属性,一个列表中绝对只能含有完全同类的元素
字符串也是一个语法糖,其完全等价于字符数组"Ciallo" == ['C','i','a','l','l','o'] == 'C':'i':'a':'l':'l':'o':[]
集合中的空集,注意:[]
、[[]]
和 [[],[],[]]
是完全不同的.第一个是空列表,第二个是包含一个空列表的列表,第三个是包含三个空列表的列表.
数组下标从0开始,下标取值:!!
1 | ghci> [9.4,33.2,96.2,11.2,23.25] !! 1 |
++
用于合并数组,两个操作数必须都是数组.
1 | ghci> "114" ++ "514" |
比较大小:同类型按字典序比较.
head
和 tail
表示列表的头部和尾部,init
和 last
表示列表的初始部分和最后一个元素.
take
从列表前面取若干元素,drop
从列表中删除前若干元素.
head _______________________tail
|[-----------------------------]
********************************
[-----------------------------]|
init________________________last
elem
判断元素是否存在于列表中.
生成数列示例:
1 | ghci> take 24 [13,26..] |
循环:
1 | ghci> take 10 (cycle [1,2,3]) |
重复:
1 | ghci> take 10 (repeat 5) |
管道符号前面的部分称为输出函数,x
是变量,N
是输入集合,x <= 10
是谓词.这意味着集合包含了所有满足谓词的自然数的两倍值.
<-
表示属于:
1 | ghci> [x*2 | x <- [1..10]] |
组合名词和形容词:
1 | ghci> let nouns = ["hobo","frog","pope"] |
_
表示任意值,仅关心其存在:
1 | length' xs = sum [1 | _ <- xs] |
与数论中对1求和相似.
过滤偶数示例:
1 | ghci> let xxs = [[1,3,5,2,3,1,2,4,5],[1,2,3,4,5,6,7,8,9],[1,2,4,2,1,6,3,1,3,2,3,6]] |
首先从 xxs
中取出每个子列表 xs
,然后再从 xs
中取出符合条件的元素.
元组
元组,tuple,可以包含列表,例如字符串.
元组更加严格,因为每种不同大小的元组都有自己的类型,所以不能编写通用函数来向元组追加元素.
没有一元元组,或者说一元元组就是单个元素本身.
fst
和 snd
只能用于二元组.
zip
自动截取:
1 | ghci> zip [5..15] ["im","a","turtle"] |
求满足条件的直角三角形:
1 | ghci> let rightTriangles' = [ (a,b,c) | c <- [1..10], b <- [1..c], a <- [1..b], a^2 + b^2 == c^2, a+b+c == 24] |