首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Haskell 基础

Haskell 基础

作者头像
Orlion
发布于 2024-09-02 08:17:47
发布于 2024-09-02 08:17:47
21900
代码可运行
举报
文章被收录于专栏:我的独立博客我的独立博客
运行总次数:0
代码可运行

第一个函数

创建doubleMe.hs文件,编写如下代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
doubleMe x = x + x

保存,打开ghci,输入

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Prelude> :l doubleMe.hs

这样我们就加载了我们的doubleMe函数,然后就可以调用这个函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Prelude> doubleMe 10
20

tip: 如果修改doubleMe.hs文件需要重新导入的话可以执行:reload doubleMe.hs或者:r doubleMe.hs重新导入

if语句

Haskell中的if语句与其他语言不同,else是不可以省略的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
doubleSmallNum x = if x > 10 then x else x * 2

Haskell 中的 if 语句的另一个特点就是它其实是个表达式,表达式就是返回一个值的一段代码:5 是个表达式,它返回 5;4+8 是个表达式;x+y 也是个表达式,它返回 x+y 的结果。正由于 else 是强制的,if 语句一定会返回某个值,所以说 if 语句也是个表达式。

List

列表由方括号以及被逗号间隔的元素组成:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Prelude> [1,2,3]
[1,2,3]

空列表:[],列表中所有元素必须是同一类型。

列表操作符

用 ++ 操作符连接两个list

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Prelude> [1,2,3] ++ [4,5,6]
[1,2,3,4,5,6]

用 : 连接一个元素到list头,它读作“cons”即construct简称

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Prelude> 1:[2,3]
[1,2,3]

但是[2,3]:1是不被允许的,因为:的第一个参数必须是单个元素,第二个参数必须是list

字符与字符串

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Prelude> "this is string"
this is string

双引号表示字符串。单个字符用”表示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Prelude> 't'
t

字符串实际是字符列表,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Prelude> 't' : "his is string"
this is string
Prelude> "this is" ++ " string"
this is string

操作

从list中取值使用!!(相当于其他语言中的arr[index])

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Prelude> let l = [1,2,3]
Prelude> l!!1
2

上面的例子就是从列表l中取下标为1的元素 list可以用来装list:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Prelude> let l = [[1,2,3], [1,2,3,4], [1,2,3,4,5]]

haskell不要求每个元素的长度一致,但要求类型必须一致

  • head函数取list第一个元素
  • tail函数取list除第一个元素之后的全部
  • last返回list最后一个元素
  • init返回一个除去list最后一个元素的全部
  • length返回list长度
  • null判断list是否为空,如果是空返回True,否则False
  • reverse 反转list
  • take 返回前几个元素
  • maximum 返回最大元素
  • minimun 返回最小元素
  • sum 返回所有元素之和,product返回积
  • elem 判断一个元素是否存在于list中,通常中缀调用 Prelude> tail [[1,2,3], [1,2,3,4], [1,2,3,4,5]] [[1,2,3,4], [1,2,3,4,5]] Prelude> init [[1,2,3], [1,2,3,4], [1,2,3,4,5]] [[1,2,3], [1,2,3,4]] Prelude> reverse [1,2,3] [3,2,1] Prelude> take 2 [1,2,3] [1,2] Prelude> 1 `elem` [1,2,3] True

Range

可以用列表符号来表示一系列元素,haskell会自动推导:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Prelude> [1..10]
[1,2,3,4,5,6,7,8,9,10]

Prelude> [1.0, 1.25, ..2.0]
[1.0,1.25,1.5,1.75,2.0]

Prelude> [1, 4, 15]
[1, 4, 7, 10, 13]

之所以没有输出15是因为15不属于我们定义的系列元素

List Comprehension

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Prelude> [x*2 | x <- [1...10]]
[2,4,6,8,10,12,14,16,18,20]

可以给这个comprehension加个限制条件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Prelude> [x*2 | x <- [1...10], x*2 > 12]
[14,16,18,20]

下面写一个函数,该函数使list中所有>10的奇数变为”BANG”,小于10的奇数变为BOOM:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
bangBoom xs = [if x > 10 then "BANG" else "BOOM" | x <- xs, odd x]

tip: odd函数判读x是否是奇数,如果是则返回True

还可以从多个list中取元素:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[x*y | x <- [1,2,3], y <- [4,5,6]]
[4,5,6,8,10,12,12,15,18]

实现自己的length函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
length' xs = sum [1 | _ <- xs]

_表示我们不会用到这个值 操作含有 List 的 List

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Prelude> 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]]
Prelude> [ [ x | x <- xs, even x ] | xs <- xxs]
[[2,2,4],[2,4,6,8],[2,4,2,6,2,6]]

Tuple

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(1,2)      (True, "a", 1)

Tuple List:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[(1,2),(3,4),(5,6)]

但是[(1,2),(3,4,5),(5,6)]是会报错的,因为元素类型不一致 两个元素的Tuple可以称为序对(Pair) Tuple不能是单元素的,因为没有意义

操作函数

fst 返回序对的首项(只能操作序对,不能操作三元组等其他数量的Tuple)

snd 返回序对的尾项

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Prudule> fst (1,2,[1,2,3])
1
Prudule> snd (1,2,[1,2,3])
[1,2,3]

zip 将两个list交叉配对生成一组Pair

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Prudule> zip [1 .. 5] ["one", "two", "three", "four", "five"]
[(1,"one"),(2,"two"),(3,"three"),(4,"four"),(5,"five")]
Prudule> zip [5,3,2,6,2,7,2,5,4,6,6] ["im","a","turtle"]
[(5,"im"),(3,"a"),(2,"turtle")]

若是两个不同长度的 List,较长的那个会在中间断开,去匹配较短的那个

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-12-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Spring IoC 源码分析 (基于注解) 一
IoC 全称为 Inversion of Control,翻译为 “控制反转”,它还有一个别名为 DI(Dependency Injection),即依赖注入。
周同学
2019/08/29
1.2K0
Spring  IoC 源码分析 (基于注解) 一
面试官:说说SpringBoot中Spring容器的启动过程
Spring家族特别庞大,对于开发人员而言,要想全面征服Spring家族,得花费不少的力气。俗话说,打蛇打七寸,那么Spring家族的“七寸”是什么呢?我心目中的答案一直都是 Spring Framework!
业余草
2020/10/10
2.9K0
面试官:说说SpringBoot中Spring容器的启动过程
Spring源码(三)-Context的创建核心逻辑(下)
由于该篇文章较多,所以就拆分为了上下两篇,接上面完成了beanFactory的信息处理,接下来是bean的相关定义的处理。
码农小胖哥
2019/12/05
6060
2.2 spring5源码 -- ioc加载的整体流程
之前我们知道了spring ioc的加载过程, 具体如下图. 下面我们就来对照下图, 看看ioc加载的源代码.
用户7798898
2020/09/27
6060
2.2 spring5源码 -- ioc加载的整体流程
逐行阅读Spring5.X源码(六) ClassPathBeanDefinitionScanner扫描器
spring包扫描是通过ClassPathBeanDefinitionScanner类来完成的,它主要工作有两个:
源码之路
2020/09/04
7080
逐行阅读Spring5.X源码(六) ClassPathBeanDefinitionScanner扫描器
Spring5源码 - 00 IOC容器创建_前期准备
这里我们分析一下AnnotationConfigApplicationContext 构造函数中的前两个方法
小小工匠
2021/08/17
2390
《Spring核心技术》第2章:@ComponentScan注解,又是三万字!!
作者:冰河 星球:http://m6z.cn/6aeFbs 博客:https://binghe.gitcode.host 文章汇总:https://binghe.gitcode.host/md/all/all.html 源码地址:https://github.com/binghe001/spring-annotation-book/tree/master/spring-annotation-chapter-02
冰河
2023/02/21
8090
《Spring核心技术》第2章:@ComponentScan注解,又是三万字!!
逐行阅读Spring5.X源码(番外篇)自定义扫描器, Mybatis是如何利用spring完成Mapper扫描的
上一篇详细讲解了spring的扫描器ClassPathBeanDefinitionScanner,本篇我们我们将模拟mybatis如何通过spring完成Mapper扫描,讲解如何通过spring编写自定义扫描器。 既然ClassPathBeanDefinitionScanner完成了spring的扫描功能,我们完全可以继承这个类来达到创建自定义扫描器的目的。
源码之路
2020/09/04
1.3K0
这一次搞懂Spring自定义标签以及注解解析原理
在上一篇文章中分析了Spring是如何解析默认标签的,并封装为BeanDefinition注册到缓存中,这一篇就来看看对于像context这种自定义标签是如何解析的。同时我们常用的注解如:@Service、@Component、@Controller标注的类也是需要在xml中配置<context:component-scan>才能自动注入到IOC容器中,所以本篇也会重点分析注解解析原理。
夜勿语
2020/09/07
5740
@ComponentScan原理分析
这是@ComponentScan的官方介绍,大致意思就是扫描注册bean的一个注解,会扫描对应路径下被@Component标注的类,和xml方式的<context:component-scan>作用相似,常用的方式是basePackages方式。
叔牙
2022/01/04
9180
@ComponentScan原理分析
从Spring源码探究IOC初始化流程
本文是基于注解的IOC初始化,不是XML!!! 代码的含义我都以注释的形式写在代码块中了,请放心查阅
向着百万年薪努力的小赵
2022/12/02
5400
【小家Spring】Spring解析@ComponentScan注解源码分析(ComponentScanAnnotationParser、ClassPathBeanDefinitionScanner)
前面我在这篇博文:【小家Spring】Spring解析@Configuration注解的处理器:ConfigurationClassPostProcessor(ConfigurationClassParser) 解释Spring解析@Configuration的时候,提到过了解析:@PropertySource、@ComponentScan、@Import…等等的解析过程。
YourBatman
2019/09/03
1.6K0
java架构之路-(spring源码篇)springIOC容器源码解析(上)
  我们这次来叭叭一下Spring的源码,这次博客主要来说说Spring源码,先粗略的撸一遍,下篇博客选几个重点去说,由于过于复杂,我也是看了一点点,我们先来过一遍源码,然后上流程图,最后我们再回头总结一下,我们来循序渐进的叭叭一下。
小菜的不能再菜
2019/10/09
3440
java架构之路-(spring源码篇)springIOC容器源码解析(上)
【小家Spring】Spring容器加载Bean定义信息的两员大将:AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner
在分析Spring IOC容器启动流程的时候,在加载Bean定义信息BeanDefinition的时候,用到了两个非常关键的类:AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner。它俩完成对Bean信息的加载。
YourBatman
2019/09/03
2.4K0
【小家Spring】Spring容器加载Bean定义信息的两员大将:AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner
SpringBoot源码解析(十):应用上下文AnnotationConfigServletWebServerApplicationContext构造方法
在前文中,我们了解了应用上下文、Bean工厂以及Bean定义的核心组件功能,接下来,我们将深入探讨应用上下文的构造方法。
Java微观世界
2025/02/11
2370
SpringBoot源码解析(十):应用上下文AnnotationConfigServletWebServerApplicationContext构造方法
Spring源码解析(二):bean容器的创建、注册默认后置处理器、bean定义扫描类
Java微观世界
2025/01/21
3760
Spring源码解析(二):bean容器的创建、注册默认后置处理器、bean定义扫描类
SpringFramework之ClassPathBeanDefinitionScanner
                                                                                         图1
克虏伯
2019/06/28
9600
SpringFramework之ClassPathBeanDefinitionScanner
从servlet容器到Spring mvc 5.1.1.RELEASE IoC 启动源码分析
容器启动会执行ServletContextListener的contextInitialized方法,对于Spring来说,它就是执ContextLoaderInitialized方法。
爬蜥
2024/02/21
1240
从servlet容器到Spring mvc 5.1.1.RELEASE IoC 启动源码分析
Spring注解Component原理源码解析
在实际开发中,我们经常使用Spring的@Component、@Service、@Repository以及 @Controller等注解来实现bean托管给Spring容器管理。Spring是怎么样实现的呢?我们一起跟着源码看看整个过程吧!
GreizLiao
2019/10/14
1.4K0
Spring注解Component原理源码解析
Spring源码:bean的生命周期(一)
本节将正式介绍Spring源码细节,将讲解Bean生命周期。请注意,虽然我们不希望过于繁琐地理解Spring源码,但也不要认为Spring源码很简单。在本节中,我们将主要讲解Spring 5.3.10版本的源代码。如果您看到的代码与我讲解的不同,也没有关系,因为其中的原理和业务逻辑基本相同。为了更好地理解,我们将先讲解Bean的生命周期,再讲解Spring的启动原理和流程,因为启动是准备工作的一部分。
努力的小雨
2024/04/30
1700
推荐阅读
相关推荐
Spring IoC 源码分析 (基于注解) 一
更多 >
LV.1
这个人很懒,什么都没有留下~
交个朋友
加入腾讯云官网粉丝站
蹲全网底价单品 享第一手活动信息
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档