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

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


判断表达式



if..then..else


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


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


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 中的等号运算符;


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 怎么写:


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 关键字,当它匹配到一个条件后,就会自动跳出;

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


模式匹配


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


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 控制台打印类型看看:


Prelude> :t (+)
(+) :: Num a => a -> a -> a
Prelude> :t (-)
(-) :: Num a => a -> a -> a

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


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

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

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

image.png

图片来源:异步社区


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

Prelude> [1,2,3,4,5]!! 1
2


再比如 mod :表示取余

Prelude> mod 7 2
1


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

Prelude> :t ($)
($) :: (a -> b) -> a -> b


用来干嘛的呢?

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

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,对于平常的编程思考也是大有裨益的,希望你有受用到~~

以上。



相关文章
|
6月前
|
Python
Python语言的表达式
Python语言的表达式
|
JavaScript 前端开发 程序员
热爱函数式的你,句句纯正的 Haskell【类型篇】
Haskell 是一门纯的函数式语言。 也就是说计算机主要是通过函数来完成的(像在数学中一样),而不是通过“先做这个,再做那个”的命令式操作顺序进行的(像在主流的编程语言中一样)。—— Simon Peyton Jones
热爱函数式的你,句句纯正的 Haskell【类型篇】
|
JavaScript 编译器
热爱函数式的你,句句纯正的 Haskell【库函数篇】
本篇是笔记篇,介绍 Haskell 的强大的库函数,也可感受下与我们平常的 js 操作异同之处:
热爱函数式的你,句句纯正的 Haskell【库函数篇】
|
编译器
热爱函数式的你,句句纯正的 Haskell【函数篇】
Haskell 值与函数是统一的,函数只是需要其他参数输入的值。如果定义的是函数,那么这个函数的行为在运行过程中也是不会改变的,对于某一个特定的输入返回的结果总是确定的,这样的函数为纯函数。
|
自然语言处理 前端开发 JavaScript
重学前端 28 # 通过四则运算的解释器快速理解编译原理
重学前端 28 # 通过四则运算的解释器快速理解编译原理
93 0
|
Shell BI 测试技术
Haskell 编程入门
在过去的几个月里,学习Haskell让我觉得非常快乐,但是入门的过程并没有我原先想象的那么简单。我非常幸运地在一个正确的地方工作,并且因此能够在Facebook参加Bryan O'Sullivan的Haskell课程。在Try Haskell上玩了一段时间后,最终你就会想要在自己的电脑上安装GHC了。
203 0
Haskell 编程入门
|
SQL 数据可视化 数据库
声明式编程和命令式编程的比较(转)
  英文原文:Imperative vs Declarative   先统一一下概念,我们有两种编程方式:命令式和声明式。   我们可以像下面这样定义它们之间的不同: 命令式编程:命令“机器”如何去做事情(how),这样不管你想要的是什么(what),它都会按照你的命令实现。
2404 1
|
C++ iOS开发 开发者
C++开发者快速学习Objective-C语言核心语法
  本文将Objective-C讨论了语言的核心语法。这部分开始详述一些具体的语法。正如你期待的一样,涉及到了定义和类。   类并不是特殊的   在Smalltalk中,类是具有一些特性的对象。在Objective-C中也一样。
978 0
下一篇
无影云桌面