热爱函数式的你,句句纯正的 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,对于平常的编程思考也是大有裨益的,希望你有受用到~~

以上。



相关文章
|
自然语言处理 前端开发 JavaScript
编译原理实战入门:用 JavaScript 写一个简单的四则运算编译器(四)结语
编译原理实战入门:用 JavaScript 写一个简单的四则运算编译器(四)结语
105 0
|
JavaScript 前端开发 程序员
热爱函数式的你,句句纯正的 Haskell【类型篇】
Haskell 是一门纯的函数式语言。 也就是说计算机主要是通过函数来完成的(像在数学中一样),而不是通过“先做这个,再做那个”的命令式操作顺序进行的(像在主流的编程语言中一样)。—— Simon Peyton Jones
热爱函数式的你,句句纯正的 Haskell【类型篇】
|
JavaScript 编译器
热爱函数式的你,句句纯正的 Haskell【库函数篇】
本篇是笔记篇,介绍 Haskell 的强大的库函数,也可感受下与我们平常的 js 操作异同之处:
热爱函数式的你,句句纯正的 Haskell【库函数篇】
|
自然语言处理 JavaScript 前端开发
【JavaScript】函数式编程:一文搞懂函数科里化(Currying)~(一)
【JavaScript】函数式编程:一文搞懂函数科里化(Currying)~(一)
|
JavaScript 前端开发 测试技术
【JavaScript】函数式编程:一文搞懂函数科里化(Currying)~(二)
【JavaScript】函数式编程:一文搞懂函数科里化(Currying)~(二)
|
编译器
热爱函数式的你,句句纯正的 Haskell【函数篇】
Haskell 值与函数是统一的,函数只是需要其他参数输入的值。如果定义的是函数,那么这个函数的行为在运行过程中也是不会改变的,对于某一个特定的输入返回的结果总是确定的,这样的函数为纯函数。
|
前端开发
前端知识案例13-javascript基础语法-算数操作符
前端知识案例13-javascript基础语法-算数操作符
55 0
前端知识案例13-javascript基础语法-算数操作符
|
前端开发
前端知识案例28-javascript基础语法-函数表达式
前端知识案例28-javascript基础语法-函数表达式
53 0
前端知识案例28-javascript基础语法-函数表达式
|
Web App开发 缓存 前端开发
✨从柯里化讲起,一网打尽 JavaScript 重要的高阶函数
✨从柯里化讲起,一网打尽 JavaScript 重要的高阶函数
|
JavaScript 前端开发
重学JavaScript之基本概念(下)=>运算符
重学JavaScript之基本概念(下)=>运算符

热门文章

最新文章