Haskell超简单自学笔记-01安装及入门编程

一、 安装Haskell编程环境:(笔者MacOS-10.15系统为例)

如果你的Mac已经有 macPort 了,直接打开终端输入:

sudo port install ghc

比网上一堆安装配置指南要简单的多。至于macPort:(官网链接:The MacPorts Project)下载对应版本即可。

二、安装好了之后,在终端输入:

即可进入交互模式;

想要退出交互模式,请输入

:q

注意冒号不能省略!!否则会找不到变量名称,报错。

进入交互模式,首先设置:

:set prompt "ghci>"

接上面的安装指南,每次打开ghci时候,都要先

:set prompt “ghci>”

//(记得前面有冒号)

下面开始编程入门:

本节重点知识点:

0-开始你的Haskell编程:

确保你的电脑有一个类似于sublime的文本编辑器,如果没有,也可以去网上随便下载一个。

打开Terminal终端

创建后缀名为.hs的空白文件(终端输入 touch xxx.hs 即可)

双击打开该文件,编写你的第一个函数。

你可以在里面用Haskell的语言编写任何你想实现的函数

例如,我们自创一个自加函数:

doubleMe x = x+x

然后保存文件,例如我们保存为一个叫baby.hs

现在换到终端里面装载该函数:

:l baby.hs

(注意此时你打开ghci的位置需要与你保存baby.hs的位置相同,否则会装载失败)

装载成功之后,我们就可以在终端里面使用我们在这个.hs文件里编写的所有函数了。

终端输入结果:

ghci> doubleMe 9 
18

更复杂的函数例如:如果一个奇数小于10就输出“xiao”,否则就输出“da”

xxx.hs:

daxiao xs = [if x<10 then "xiao!" else "da!" | x <- xs, odd x] 
--在.hs 文件里面的单行注释,用 两个短杠 开头即可 
--这里的odd用来判断是否为奇数 
--这里的xs需要是一个List

终端:[7..20]表示7~20的一个List

ghci>daxiao [7..20] 
["xiao!","xiao!","da!","da!","da!","da!","da!"]

1-中缀函数:

比如“*”号 就是一个将两个数相乘的函数,就像三明治一样,用两个参数将它夹在中央,这被称作中缀函数。而其他大多数不能与数夹在一起的函数则被称作前缀函数。

例如取两个整数相除所得商的div函数,div 90 10可得9,但这种形式不容易理解:究竟是哪个数是除数,哪个数被除?使用中缀函数的形式 90 `div` 10 就更清晰了:

在haskell中,函数的调用必使用空格,例如bar (bar 3),在C中,就相当于bar(bar(3))

2-If then else 语法结构:

haskell中if语句的else部分是不可省略。在haskell中,每个函数和表达式都要返回一个结果。

例如:

doubleSmallNumber' x = (if x >100 then x else x*2) + 1

终端:

ghci>doubleSmallNumber' 50 
101

3.1-List

在ghci下执行let a =1与在脚本中编写a=1是等价的。

ghci>let a=1 
ghci>let b=2 
ghci>a+b 
3

同理声明一个list:

ghci>let babylist = [1,2,3,4,5,6] 
ghci>babylist 
[1,2,3,4,5,6]

List是一种单类型的数据结构,List可以用来存储多个类型相同的元素。

list通常用中括号包含元素并用逗号隔开,但是字母也可以用双引号

"Hello" = ['h','e','l','l','o']

两个List合并是很常见的操作,这可以通过使用两个list名字中间进行++运算符实现

往一个List前端插入单个元素也可以用中缀函数冒号

ghci>"A" : "BCD" 
// 此处用双引号A会报错 <interactive>:3:7: error: • Couldn't match type ‘Char’ with ‘[Char]’ Expected type: [[Char]] Actual type: [Char] • In the second argument of ‘(:)’, namely ‘"BCD"’ In the expression: "A" : "BCD" In an equation for ‘it’: it = "A" : "BCD" 


ghci>'A' : "BCD" 
"ABCD" 
// 用单引号即可完成前端插入

(⚠️注意: 冒号前面的是要插入的单个元素,所以要用单引号,冒号后面的是list;而++函数前后都是list)

若是要按照索引取得List中的元素,可以使用 !! 运算符,索引的下标从0开始记。

ghci> "Steve Buscemi" !! 6 
'B'

当List内装有可比较的元素时,使用 > 和 >=可以比较List的大小。它会先比较第一个元素,若它们的值相等,则比较下一个,以此类推。

ghci> [3,2,1] > [2,1,0] 
True

3.2-llist的常用函数

list的前缀函数:

Head返回一个List的头部,也就是List的首个元素。

Last返回一个LIst的最后一个元素。

Tail返回一个LIst的尾部,也就是List除去头部之后的部分。

Init返回一个LIst除去最后一个元素的部分。

length返回一个List的长度。

Null检查一个List是否为空

reverse将一个List反转

take返回一个List的前几个元素,例如: take 3 取前三个元素

drop与take的用法结构相同,它会删除一个List中的前几个元素。

maximum返回一个List中最大的那个元素。minimun返回最小的。

Sum返回一个List中所有元素的和。product返回一个List中所有元素的积。

list的中缀函数:

elem判断一个元素是否在包含于一个List,通常以中缀函数的形式调用它。

ghci> 4 `elem` [3,4,5,6]

True

当然也可以用infix expression:

ghci>elem 4 [1,4,5] 
True

3.3-List的构造

Range(区间) 是构造 List 方法之一:

中括号里面两个“ .. ” ~

要得到包含 1 ~ 20 中所有自然数的List,只要 [1 . . 20] 即可

Range有点聪明,允许你申明一个步长。要得到1到20间所有的偶数或者3的倍数该怎样?

ghci> [3,6..20] 
[3,6,9,12,15,18]

就是说,range能判断简单的list元素排列规律,比如 3 ->6 是 3*1 -> 3*2

仅需用逗号将前两个元素隔开,再标上上限即可

取前24个13的倍数该怎样?恩,你完全可以 [ 13 , 26 . . 24 * 13 ] ,但有更好的方法:take 24 [ 13 , 26 . . ] 。

在 Range 中使用浮点数要格外小心!出于定义的原因,浮点数并不精确。

cycle 生成无限 List 的函数

ghci> take 10 (cycle [1,2,3]) 
[1,2,3,1,2,3,1,2,3,1]

Haskell是惰性的,不会一直循环下去。它会等着,看你会从它那儿取多少。

Repeat 接受一个值作参数,并返回一个仅包含该值的无限 List,这与用 cycle 处理单元素List差不多。

Replicate 可以再生如 replicate 3 10,得[ 10,10,10 ]。

list comprehension

它与 set comprehension 十分的相似,用它取前十个偶数轻而易举。这个 list comprehension 可以表示为:

ghci> [x*2 | x <- [1..10]] 
[2,4,6,8,10,12,14,16,18,20]

等价于集合的写法:

编辑

x属于整数且x小于等于10,所有2*x的集合

例如取 50 到 100 间所有除 7 的余数为 3 的元素:

ghci>[x|x<-[50..100],x `mod` 7 == 3] 
[52,59,66,73,80,87,94]

List filtering

从一个 List 中筛选出符合特定限制条件的操作也可以称为过滤(flitering)。

eg.1.写一个我们自己的list长度计算函数Length‘:

length' xs = sum [1 | _ <- xs] 
--_ means that we don't care what we'll draw from the list anyway so instead of writing a variable name that we'll never use, we just write _

这个length函数将一个 List 中所有元素置换为1,并且使其相加求和sum;得到的结果便是我们的 List 长度。

eg.2.除去字符串中所有非大写字母的函数

removeNonUppercase st = [ c | c <- st, c `elem` ['A'..'Z']]

嵌套list comprehension

除去所有奇数(odd是判断奇数,even是判断偶数)

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

ghci> [ [ x | x <- xs, even x ] | xs <- xxs] [[2,2,4],[2,4,6,8],[2,4,2,6,2,6]]

4-Tuple (元组)

很像 List -不同之处就是 Tuple 中的项不必为同一类型,在 Tuple 里可以存入多类型项的组合。

在 haskell 中表示二维向量:长度为 2 的 Tuple (也可以称作序对,Pair)

1-用List中括号嵌套表示:[[1,2],[8,11],[4,5]]

2-用List包含Pair表示:[(1,2),(8,11),(4,5)]

第二种方法的好处是,pair作为list里面的元素存在,list又只能存储单一类型的元素。防止像第一种方式那样出现:

[[1,2],[8,11,5],[4,5]]

虽然语法不存在问题,但是却与我们的创建的目的不符。

Tuple 可以用来储存多个数据,如,我们要表示一个人的名字与年 龄,可以使用这样的 Tuple : ( " Christopher " , " Walken " , 55 )。从这个例子里也可以看出,Tuple 中也可以存储 List 。

使用 Tuple 前应当事先明确一条数据中应该由多少个项。每个不同长度的 Tuple 都是独立的类型

可以有单元素的 List ,但 Tuple 不行。

声明一个二元Tuple:

ghci>(8,2) 
(8,2)

相关函数

fst返回一个序对的首项。

ghci> fst (8,11) 
8 
ghci> fst ("Wow", False) 
"Wow"

snd 返回序对的尾项。

这两个函数仅对序对有效!

Tuple中取数据的所有方式:

Zip函数:它可以用来生成一组序对 (Pair) 的 List;它取两个 List ,然后将它们对应配对,形成一组序对的 List

(尤其是你需要组合或是遍历两个 List时):

ghci> zip [1,2,3,4,5] [5,5,5,5,5] 
[(1,5),(2,5),(3,5),(4,5),(5,5)] 

ghci> zip [1 .. 5] ["one", "two", "three", "four", "five"] 
[(1,"one"),(2,"two"),(3,"three"),(4,"four"),(5,"five")]

解决问题:

如何取得所有三边长度皆为整数且小于等于10,周长为 24 的直角三角形?首先,把所有三遍长度小于等于 10 的三角形都列出来:(对象设一个三元组(a,b,c))

let triangles = [ (a,b,c) | c <- [1..10], b <- [1..10], a <- [1..10] ]

然后修改参数变成直角(利用勾股定理):

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] 
ghci> rightTriangles' [(6,8,10)]

这便是函数式编程的一般思路:先取一个初始的集合并将其变形,执行filtering条件,最终取得正确的结果。

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值