前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >热爱函数式的你,句句纯正的 Haskell【表达式篇】

热爱函数式的你,句句纯正的 Haskell【表达式篇】

作者头像
掘金安东尼
发布2022-09-19 11:11:12
1.1K0
发布2022-09-19 11:11:12
举报
文章被收录于专栏:掘金安东尼

theme: juejin

判断表达式

if..then..else

表达式是编程语言中最常用到的基础之一,本片让我们来看看在 Haskell 中表达式是怎样的?

先看个小例子感受一下(依然是借助编译器 GHC):

代码语言:javascript
复制
Prelude> isTwo n = if n==2 then True else False
Prelude> isTwo 2
True
Prelude> isTwo 3
False
Prelude> :t isTwo
isTwo :: (Eq a, Num a) => a -> Bool

这是一个非常简单的 if..then..else 表达式,isTwo 是一个函数,n 是入参;可以看到,Haskell 的表达式并没有像在 JS 中的括号进行包裹;

当然,你也可以写像 JS 中的等号运算符;

代码语言:javascript
复制
Prelude> isFive = (==5)
Prelude> isFive 5
True
Prelude> :t isFive
isFive :: (Eq a, Num a) => a -> Bool

和 JS 还有一个大不同是:Hskell 里的 if..then..else 的 else 后的表达式不可省略;

也就是说,必须定义条件成立的时候返回的值,也必须定义条件不成立的时候返回的值,并且两者返回的类型必须相同,这样一定程度上保证了函数定义的完整性。

实际上,if..then..else 是一种结构性的表达式,也可以理解为一种运算符,属于:混合位置运算符

而普通的加法,处于两个参数中间,称为:中缀运算符

函数,位于一个参数前面,可理解为:前缀运算符

函数式编程的“输入 => 计算 => 得值”的思想处处都有体现;

switch

看了 if else ,再看看 switch 怎么写:

代码语言:javascript
复制
Prelude> :{
Prelude| week n = case n of
Prelude|     1 -> "Mon"
Prelude|     2 -> "Tues"
Prelude|     3 -> "Wed"
Prelude|     4 -> "Thurs"
Prelude|     5 -> "Fri"
Prelude|     6 -> "Sat"
Prelude|     7 -> "Sun"
Prelude|     _ -> error "invalid"
Prelude| :}
Prelude> week 4
"Thurs"

Haskell 中无需 break 关键字,当它匹配到一个条件后,就会自动跳出;

_ 下划线是定义默认的其它条件;

模式匹配

还有另一种方式可以表达条件运算 —— 模式匹配;

代码语言:javascript
复制
Prelude> :{
Prelude| abs4 n
Prelude|     | n > 4 = n
Prelude|     | otherwise = -n
Prelude| :}
Prelude> abs4 2
-2
Prelude> :t abs4
abs4 :: (Ord p, Num p) => p -> p

| 将函数的参数按特定的条件分开;

在模式匹配中,更精确更有指向性的模式总是放在相对通用和宽泛的模式前面(优先匹配);

本瓜觉得跟这里的 模式匹配责任链模式 有点类似,按照顺序去匹配,把更有可能正确的条件判断放在最前,优先去执行判断,满足条件立即跳出;

不过 JS 实现责任链要进行封装,Haskell 直接原生语法就支持| 就是对 if..then..else 的封装;

运算符

前文已提到:加号、减号等,这些本质和函数是一样的,函数也是运算符,加减号也是函数!

可以在 GHC 控制台打印类型看看:

代码语言:javascript
复制
Prelude> :t (+)
(+) :: Num a => a -> a -> a
Prelude> :t (-)
(-) :: Num a => a -> a -> a

只不过它们属于不同位置的运算符(前缀、中缀、后缀、混合位置);

实际上,运算符共有 3 个属性

    1. 优先级(在 Haskell 中,有十个优先级(0 ~ 9));
    1. 结合性(分为左结合、右结合、无结合);
    1. 位置(前、中、后、混合);

提供一个优先级和结合性的表:

image.png
image.png

图片来源:异步社区

比如运算符 !! :表示从一个列表中取出第 n 个元素(从 0 开始)

代码语言:javascript
复制
Prelude> [1,2,3,4,5]!! 1
2

再比如 mod :表示取余

代码语言:javascript
复制
Prelude> mod 7 2
1

有一个很重要的运算符要特别提醒:$

代码语言:javascript
复制
Prelude> :t ($)
($) :: (a -> b) -> a -> b

用来干嘛的呢?

当你想定义 f (g (h x)) 时,可以简写为 f g h x ,这样写函数的连续调用更轻便、易读;

代码语言:javascript
复制
Prelude> let f1 = (*2)
Prelude> let f2 = (+1)
Prelude> f1 $ f2 7
16

自右向左调用,回答了之前 compose 自右向左调的原因:与函数书写的嵌套顺序一致;

!、

小结

本篇我们又学习了 Haskell 的新的知识点:

  1. if else 是怎么写的,与 JS 差异在哪;
  2. switch 是怎么写的,与 JS 差异在哪;
  3. 模式匹配(与责任链模式类似);
  4. 函数与运算符等价(非常重要)
  5. 运算符的三个属性;
  6. 一些特殊的运算符,比如:!!$ 等;

这些都是为后面揭开 Haskell 函数式编程神秘面纱的基础,期间也能一窥这种把函数当计算的奇妙之处,即使不能在开发生产中用到 Haskell,对于平常的编程思考也是大有裨益的,希望你有受用到~~

以上。

我是掘金安东尼,公众号同名,输出暴露输入,技术洞见生活,再会~

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • theme: juejin
  • 判断表达式
    • if..then..else
      • switch
        • 模式匹配
        • 运算符
        • 小结
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档