小白入门Haskell 语言

Haskell 语言

安装

因为我是 Windows 系统,在这里下载一个 GHC for Win 后解压缩,将解压缩后的目录中的 bin 添加到环境变量的 Path 中,在命令行中输入 ghci 就可用交互式的了。

其中 bin 目录下有一个 runhaskell.exe 文件,我们对一个后缀为 .hs 的文件应用这个可执行文件后,就能写下面的代码了,而不是在 ghci 中交互,虽然那样学习更方便。

学习

四则运算

值得一提的是除法,我们可以写出如下 main 函数并打印结果,如

main = do print (5 / 2)

结果为 2.5 而不是 Cpp 中的 2 ,如果我们需要欧几里得除法则可以这样写

main = do print (5 `div` 2) -- div 5 2 也是一样的

结果为 2 而取模也不是通常的 % 符号而是

main = do print (5 `mod` 2) -- mod 5 2 也是一样的
布尔值

TrueFalse 表示,用 not 表示取反, && 表示逻辑与, || 表示逻辑或,如

main = dolet c = 10if not (c > 11)then putStr "c <= 10"else putStr "c > 11"

需要注意括号的位置,基本上我们可以认为 not 是一个函数。

比较两个数

main = dolet c = 10if 5 /= cthen putStr "c not eqaul to 5"else putStr "c is 5"

注意这里的不等于使用的是 a /= b 而不是 a != b ,而等于则为 a == b 与其他语言是类似的。

一些基本函数
main = do print (succ 8) -- 9
main = do print (min 10 11) -- 10
main = do print (max 10 11) -- 11

函数的一些顺序有下面这个例子

main = do print (succ 9 + max 5 4 + 1)

这等价于

main = do print ((succ 9) + (max 5 4) + 1)
编写自己的函数
doubleMe x = x + x
main = doprint (doubleMe 9) -- 18
squareMe x = x * x
main = doprint (squareMe 9) -- 81

当然也可以用小数调用这些函数如

doubleMe x = x + x
main = doprint (doubleMe 9.1) -- 18.2

也就是说我们写的函数实际上是一个泛型的函数!这很棒,对于限制类型后面会提到。

多参数的函数

addxy x y = x + y
main = doprint (addxy 7 8) -- 15

带有 if 的函数

plusOne x = if x == 0 then x + 1 else -1
main = doprint (plusOne 1)print (plusOne 0)

当然我们可以调整一些缩进写成

plusOne x =if x == 0then x + 1else -1main = doprint (plusOne 1)print (plusOne 0)

这样使得代码更具有可读性。

list

我不清楚是否应该称呼其为数组,我们可以写出这样的代码

main = dolet c = [1,2,3,4]print c -- [1,2,3,4]

而我们常用的字符串如 "abc" 实际上为 ['a','b','c'] 的语法糖,这与在 C 语言中有点类似,也就是说

main = doprint ("abc" == ['a','b','c']) -- True

是毫无疑问的。

对于 list 拼接也显得很自然,有

c = [1,2,3] ++ [2,3,4]
main = doprint c -- [1,2,3,2,3,4]

也有这样的拼接方法如

a = 10
b = [1,2,3]
main = doprint (a : b) -- [10,1,2,3]

下标访问,在 C 语言中我们常常会这样写

#include <stdio.h>
int main(void) {int a[10];printf("%d", a[1]); // 未初始化,值可能为随机return 0;
}

而在 Haskell 中则是

a = "abcdefg"
main = doputChar (a !! 2) -- c

我们发现其索引开始也是 0 ,这与一般的习惯很符合。

值得注意的是, list 之间也可以通过 <>>=<= 比较,结果好像为字典序(但一般很少用到)。

head 函数只取首个元素

c = [1,2,3,4,5]
main = doprint (head c) -- 1

tail 函数为除了首个元素的其余元素的 list

c = [1,2,3,4,5]
main = doprint (tail c) -- [2,3,4,5]

last 函数为最后一个元素

c = [1,2,3,4,5]
main = doprint (last c) -- 5

init 函数为除了最后一个元素的其余元素的 list

c = [1,2,3,4,5]
main = doprint (last c) -- [1,2,3,4]

注意, head 不能应用于空的 list ,其余函数我没有测试。

length 函数返回 list 的长度

main = doprint (length [1,2,3]) -- 3print (length []) -- 0

null 函数返回一个布尔值表示 list 是否为空

main = doprint (null []) -- Trueprint (null [1]) -- False

reverse 函数返回一个翻转的 list

c = [1,2,3]
main = doprint (reverse c) -- [3,2,1]

上面所说的函数全都是一个参数的函数,且参数都为 list ,下面的函数为两个参数,具体看示例为

take 函数表示截取前几个元素组成新的 list

c = [1,2,3,4,5]
main = doprint (take 3 c) -- [1,2,3]print (take 0 c) -- []print (take 8 c) -- [1,2,3,4,5]

drop 函数表示丢弃前几个元素组成新的 list

c = [1,2,3,4,5]
main = doprint (drop 3 c) -- [4,5]print (drop 0 c) -- [1,2,3,4,5]print (drop 100 c) -- []

maximum 函数与 minimum 函数想必不必多说

c = [1,2,3,4,5]
main = doprint (maximum c) -- 5print (minimum c) -- 1

sum 函数返回和

c = [1,2,3]
main = doprint (sum c) -- 6

product 函数返回乘积

c = [1,2,3]
main = doprint (product c) -- 6

elem 函数告诉我们这个元素是否在 list 中

c = [1,2,3]
main = doprint (1 `elem` c) -- Trueprint (-1 `elem` c) -- False

通常用一个中缀表达式来写,当然也可以写作 elem 1 c ,因为更自然,与之前的 divmod 是类似的。

范围的 list 可以这样写

main = doprint [1..5] -- [1,2,3,4,5]print [2,4..10] -- [2,4,6,8,10]print [3,6..20] -- [3,6,9,12,15,18]

但是不能写 [5..1] 而必须写 [5,4..1] ,我们可以理解为等差数列前两项以及最后一项,但小数的时候不同

main = doprint [0.1,0.3 .. 1] -- [0.1,0.3,0.5,0.7,0.8999999999999999,1.0999999999999999]

cycle 函数可以将一个东西无限制的拼接如

main = doprint (take 10 (cycle [1,2,3])) -- [1,2,3,1,2,3,1,2,3,1]

于是我们只能用 take 函数将其取出部分。

repeat 函数则有

main = doprint (take 10 (repeat 5)) -- [5,5,5,5,5,5,5,5,5,5]

也有更方便的函数 replicate 可以做到

main = doprint (replicate 3 10) -- [10,10,10]

接下来是一个很厉害的工具,可以制作我们想要的 list 形态,例如我想要 {x∣0≤x≤20,xmod3=1,x∈Z}\{x\mid 0\leq x\leq 20,x\bmod 3=1,x\in\mathbb{Z}\}{x0x20,xmod3=1,xZ} 的 list 可以写

main = doprint [x | x <- [0..20], x `mod` 3 == 1]

这甚至与数学中很类似。

我们也可以写函数接收一个 list 返回出想要的 list 如

weWant xs = [x | x <- xs, odd x]
main = doprint (weWant [0,1,7,9]) -- [1,7,9]

上面用到了函数 odd 同样的也有 even

不止如此,我们也可以写出

prodEachElem xs ys = [x * y | x <- xs, y <- ys]
main = doprint (prodEachElem [1,2,3] [4,5,6]) -- [4,10,18]

用数学表达则为 x={1,2,3},y={4,5,6},z={ab∣a∈x,b∈y}x=\{1,2,3\},y=\{4,5,6\},z=\{ab\mid a\in x,b\in y\}x={1,2,3},y={4,5,6},z={abax,by} 很自然。

回顾之前的函数 length 我们可以用 sum 写一个自己的版本为

length' x = sum [1 | _ <- x]
main = doprint (length' []) -- 0print (length' [1,2,3]) -- 3

他可以正常的工作,其中下划线 _ 代表我们并不关心这个是什么。

tuple

中文一般为元组。元组一般为 (a,b) 这样的形式。

fst 函数返回元组中的首个元素,而 snd 返回第二个。

main = doprint (fst (1,"WWW")) -- 1print (snd (2,"WWWA")) -- "WWWA"

有一个很酷的函数为 zip 可以制作元组如

main = doprint (zip [1,2,3] ["A","B","C"]) -- [(1,"A"),(2,"B"),(3,"C")]print (zip [1..3] ['A','B','C']) -- [(1,'A'),(2,'B'),(3,'C')]print (zip [1..] ['A','B']) -- [(1,'A'),(2,'B')]

可以看到是以 length 较短的标准制作的,这样的话写出 [1..] 这样看似无穷多的 list 也变得合理了(惰性?)。

当然,元组也远远不止两个元素,也可以写出

d = [(a,b,c) | a <- [1,3..10], b <- [2,4..7], c <- [7,11..18]]
main = doprint d

注意这里并不是 zip 函数,所以不要写无穷无尽的,我们可以将这里视为三重的循环体。刚刚出了事故我的电脑死机了,看来这个编译器会一丝不苟的执行下去呢,并没有检测是否会造成死循环。

类型

参考资料

[1] http://learnyouahaskell.com/chapters

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/443920.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

兔老大的系统设计(二)定时系统(延时队列)

之前文章&#xff1a; 兔老大的系统设计&#xff08;一&#xff09;健康度系统 一、背景 延迟队列的应用场景非常广泛&#xff0c;如客户主动操作&#xff1a; 股票定投顾客预约场景会员定时续费/缴费CSDN定时发布或系统内部操作&#xff1a; 订单成功后&#xff0c;在30分…

作为软件工程师,你必须知道的20个常识

作为一名优秀是软件开发工程师&#xff0c;以下的这些常识你知道吗&#xff1f;在实际工作中有没有总结过呢&#xff1f;小编就带大家一起分享这20个软件开发常识。 1、针对面向对象的设计与分析&#xff1a;为了让软件有更好的可维护性&#xff0c;重用性以及快速开发&#xf…

新鲜美团测试岗面经(带答案)

1、测试环境搭建过程 2、 验证环境部署是否成功时 跑测试用例 接口是什么样的&#xff1f;&#xff08;服务对外提供的调用接口&#xff09; 3、 数据库 表 有个字段 name字段 nameliuguoge 唯一标识id3 修改nameguogeliu update user set nameguogeliu where id3; 4、写…

如何实现两个数据库之间的同步

两台服务器分别架在两个不同的机房&#xff0c;要实现所有表中数据的同步&#xff0c;延时一两分钟没关系&#xff0c;数据库数据量很大&#xff0c;表大概有不到一百个吧&#xff0c;怎么实现同步&#xff1f;不同服务器数据库之间的数据操作--创建链接服务器 execsp_addlink…

博弈论经典入门

文章目录博弈论常见模型必胜点和必败点的概念&#xff1a;必胜点和必败点的性质&#xff1a;巴什博弈斐波那契博弈威佐夫博弈尼姆博弈SG函数与SG定理博弈论 博弈论 &#xff0c;是经济学的一个分支&#xff0c;主要研究具有竞争或对抗性质的对象&#xff0c;在一定规则下产生的…

百度校园招聘历年经典面试题汇总:Java开发岗

&#xff08;1&#xff09;、Java中的多态 &#xff08;2&#xff09;、Object类下的方法 &#xff08;3&#xff09;、Finalize的作用和使用场景 &#xff08;4&#xff09;、Hashcode和equals &#xff08;5&#xff09;、为什么要同时重写hashcode和equals&#xff0c;不同时…

如何实现Oracle数据库之间的数据同步?

我们都知道&#xff0c;在Oracle数据库的管理与开发工作中&#xff0c;总会存在着一些表数据和基础资料数据&#xff0c;这时需要有效的将这些数据库进行同步合并&#xff0c;有没有什么简单的方法可以实现Oracle数据库之间的数据同步呢&#xff1f;在此诚恺科技重庆服务器频道…

c++面试题总结1

内存结构 堆&#xff1a;由程序员手动分配和释放&#xff0c;完全不同于数据结构中的堆&#xff0c;分配方式类似链表。由malloc&#xff08;c语言&#xff09;或new&#xff08;c&#xff09;来分配&#xff0c;free&#xff08;c语言&#xff09;和delete&#xff08;c&…

JBPM4.4整合SSH2项目

一&#xff1a;导入相应的jar包: *注意事项&#xff1a; (1).与项目中的jar包不能出现冲突 (2).版本应一致 jbpm-bpmn.jar jbpm-console-form-plugin.jar jbpm-console-graphView-plugin.jar jbpm-console-integration.jar jbpm-console-reports.jar jbpm-db.jar jbpm-example…

Linux简单命令收录(who,echo,date)【上】

shell严格区分输入命令的大小写&#xff0c;如who、Who和WHO是不同的&#xff0c;其中只有全小写——who是正确的Linux命令。 命令与选项和参数之间要用空格或制表符隔开。连续空格会被shell解释称单个空格。 选项&#xff1a;对命令的特殊定义&#xff0c;以“-”开始&#…

移动端测试面试题目大全

ADB工作原理 当用户启动一个adb客户端&#xff0c;客户端首先确认是否已有一个adb服务进程在运行。如果没有&#xff0c;则启动服务进程。当服务器运行&#xff0c; adb服务器就会绑定本地的TCP端口5037并监听adb客户端发来的命令&#xff0c;所有的adb客户端都是用端口 5037与…

Linux简单命令收录(cal,passwd,clear)【下】

1、cal NAME cal - display a calendar 显示日历 SYNOPSIS cal [options] [[[day] month] year] cal [options] [timestamp|monthname] 用法&#xff1a; cal [选项] [[[日] 月] 年] cal [选项] <时间戳|月份名> OPTIONS -1…

web知识点大总结

#第一章 Web基础知识 Web开发基本概念 1、万维网是一个由许多相互链接的超文本组成的系统&#xff0c;通过互联网访问。 2、web&#xff1a;worldwideweb&#xff0c;万维网&#xff0c;简称web&#xff0c;www&#xff0c;通常称为网页。 3、web开发&#xff1a;进行网页页…

Linux命令集—— cat AND more

1、cat NAME cat - concatenate files and print on the standard output 连接所有指定文件并将结果写到标准输出。【经常用来显示文件的内容&#xff0c;类似DOS的TYPE 命令】 SYNOPSIS cat [OPTION]... [FILE]... cat [选项]... [文件]... With no FILE, or when FILE…

Linux简单命令集——less

NAME less - opposite of more more的对立面 注意 与more命令类似&#xff0c;less命令也用来分屏显示文件的内容&#xff0c;但是less命令允许用户向前或向后浏览文件。例如&#xff0c;less命令显示文件内容时&#xff0c;可以用⬆键和⬇键分别将屏幕内容下移一行和上移一…

《重构-改善既有代

重要列表 1、如果你发现自己需要为程序添加一个特性&#xff0c;而代码结构使你无法很方便地达成目的&#xff0c;那就先重构哪个程序&#xff0c;使特性的添加比较容易的进行&#xff0c;然后再添加特性 2、重构前&#xff0c;先检查自己是否有一套可靠的测试机制&#xff0…

Myeclipse 6.5 优化

1、取消自动validation validation有一堆&#xff0c;什么xml、jsp、jsf、js等等&#xff0c;我们没有必要全部都去自动校验一下&#xff0c;只是需要的时候才会手工校验一下&#xff01; 取消方法&#xff1a; windows–>perferences–>MyEclipse Enterprise Workbench–…

Linux简单命令集——head

NAME head - output the first part of files 输出文件的第一部分SYNOPSIS head [OPTION]... [FILE]...head [选项]... [文件]...head命令在屏幕上显示指定文件file的开头若干行&#xff0c;行数由参数值来确定。显示行数的默认值是10。-c, --bytes[-]NUM print the firs…

操作系统中避免死锁的银行家算法【表面C++实际C语言】一学就废的菜鸡代码

文章目录银行家算法实验原理数据结构初始化输出资源分配量安全性算法银行家算法完整代码测试数据测试结果第一题第二题银行家算法 银行家算法是一种最有代表性的避免死锁的算法。在避免死锁方法中允许进程动态地申请资源&#xff0c;但系统在进行资源分配之前&#xff0c;应先…

GitHub 使用指南

目录切换分支删除已有文件只删除远程仓库中的文件&#xff0c;不删除本地仓库中的文件同时删除远程仓库和本地仓库中的文件提交文件git查看本地分支连接的是哪个远程分支切换分支 查看本地和远程所有分支 git branch -a当前本地分支为绿色&#xff0c;当前所在分支前带有“*”号…