热爱函数式的你,句句纯正的 Haskell【类型篇】

简介: Haskell 是一门纯的函数式语言。 也就是说计算机主要是通过函数来完成的(像在数学中一样),而不是通过“先做这个,再做那个”的命令式操作顺序进行的(像在主流的编程语言中一样)。—— Simon Peyton Jones


Haskell 是一门纯的函数式语言。 也就是说计算机主要是通过函数来完成的(像在数学中一样),而不是通过“先做这个,再做那个”的命令式操作顺序进行的(像在主流的编程语言中一样)。—— Simon Peyton Jones


初见😀



什么是 Haskell ?我们从 wiki 上可以找到以下要点:


  • Haskell 是一种标准化的,通用的纯函数式编程语言,有惰性求值和强静态类型;
  • 在Haskell中,“函数是第一类对象”。作为一门函数编程语言,主要控制结构是函数
  • Haskell具有 “证明即程序、命题为类型” 的特征;


这些概念起初可能看起来空泛,但回过头来看:“它还真就是这样!”


调试🎇



目前 Haskell 的主要编译器是 GHC,下载地址,你可以创建 .hs 文件,用 Notepad++ 打开。


GHCi 是 GHC 的一部分,可以解析、调试 Haskell 程序。

image.png


认识下 GHCi 中的命令:

  • :l 用来导入当前路径或者指定路径下的文件;
Prelude> :l "C:\\Users\\ User\\Desktop\\HelloWorld\\HelloWorld.hs"
  • :r 用来重新导入当前的源代码文件;
  • :cd 改变当前GHCi的路径;
Prelude> :cd C:\Users\User\Desktop
  • :edit 用默认的文本编辑器编辑当前导入的文件;


更多命令可见:官网


HelloWorld🌎



对于每个程序员来说,Hello,World 都是神圣的!


可以直接在调试器内打印:

putStrLn "Hello,World!"


也可以新建一个文件:Helloworld.hs

然后 :l 引入,输入 main 运行:


Prelude> :l D://ghc-haskell//test.hs
*Main> main
Hello,World!


也可以通过 :cd 命令,输入 runghc ,将 .hs 文件变成 .exe 文件执行;


类型🍕



Haskell 的类型属于强类型,即每一个数据或每一个函数都有非常精确、严格的类型。

注:我们使用命令 :t 来查看类型;


Haskell 常用数据类型有:

  • Bool

布尔类型只有 True 和 False 两个值,注意大小写;同样支持“或与非”运算:

True||False
True&&False
not True


  • Char

字符型,与其它语言一致

Prelude> :t "str"
"str" :: [Char]


  • Int

有符号整数,它的范围与操作系统和 GHC 位数有关。


  • Word

无符号整数,Haskell 中的 Word 相当于 C 语言里的 unsigned int 类型;


  • Integer

任意精度整数;


  • Float

单精度浮点数;


  • Double

双精度浮点数;


  • Rational

有理数类型 Rational,即用两个任意精度的整数来表示一个小数,这在做高精度数学运算时有很多好处;


Prelude> 0.75::Rational
3 % 4


  • String

字符串类型,String 是一个 Char 的列表。

在 GHCi 里输入['H', 'e', 'l', 'l','o'],会得到 "Hello"


Prelude> ['H', 'e', 'l', 'l','o']
"Hello"


  • tuple

元组类型,如:(7758,True,"HelloWorld"),各种类型可以互相组合使用;

以上,都是基础的类型,可一眼带过~


函数类型!🍻



函数类型是本篇的重中之重,前面的可以随意看看,但是从此节开始请务必细究。

函数可以理解为从参数到结果的一个映射,比如T1 -> T2。每一个函数都符合这样一个

定义;


add::(Int,Int)->Int // 声明 add 函数,输入是一个元组类型,元组内是两个 Int 元件,输出是一个 Int 类型;
add (x,y) = x + y // add 的具体实现


也可以这样直接在命令行中定义:


Prelude> let add(x,y) = (x + y) ::Int
Prelude> add(1,2)
3


若 T1 或 T2 为函数,那么 T1-> T2 函数可以称为高阶函数;这也是之前说过的,将函数作为输入或输出的函数称为高级函数


  • Haskell 柯里化

显然,两数相加传 2 个 Int 的元组,三个数相加传 3 个 Int 的元组,四个数相加,传 4 个 Int 的元组...... 这是非柯里化的,传参有极大麻烦;


add3::(Int,Int,Int)->Int
add4::(Int,Int,Int,Int)->Int


Haskell 定义了柯里化(curry)函数来帮助我们改善这一点:

Prelude> :t curry
curry :: ((a, b) -> c) -> a -> b -> c


// 实现加法的柯里化,支持多项连续相加,且不用提前声明项数;

Prelude> let add(x,y) = (x + y) ::Int
Prelude> curry add(curry add((curry add)1 2)3)4
10


这个是真滴强👍

image.png


  • 多态函数

多态函数在 Haskell 中非常常见:


Prelude> head[1,2,3]
1
Prelude> head[True,False]
True
Prelude> head"Hello"
'H'
Prelude> zip[1,2,3][4,5,6]
[(1,4),(2,5),(3,6)]
[('a',1),('b',2),('c',3)]
Prelude> fst(5,True)
5
Prelude> snd(5,True)
True


  • 重载类型函数

5 一直是被当成整数。但是,它还可以是一个任意精度整数,或是一个小数。这样一来,类型上可能会有一些不协调,因为 5 是一个有着很多类型的值,Haskell 中用类型类(typeclass)这一概念来对这些类型做了细致的分类。


我们在下一小节做更为细致的说明“类型类”~


  • 类型别名

一个数据的类型可以由多个其他的类型组成,在 Haskell 中,可以用 type 关键字将这些复杂的类型替换成为其他简单的名字;


Prelude> type RGB=(Int,Int,Int)
Prelude> let rgb=(255,255,255) ::RGB
Prelude> :t rgb
rgb :: RGB


这样处理后,你能更清楚这个变量是干什么的~


类型类!!🖖



在控制台输入 :t 5 查看输出:

Prelude> :t 5
5 :: Num p => p


5 是 Num 类型类,这个数可以是整数,也可以是小数或其他数类型;

  • => 是类型类的限定符号;

Haskell 除了 Num 类型类以外,还有Eq、Ord 和 Show 类型类等等;


// 判断是否相等 Eq 类型类
Prelude> :t (==)
(==) :: Eq a => a -> a -> Bool
// 判断大小 Ord 类型类
Prelude> :t (<)
(<) :: Ord a => a -> a -> Bool
// 使用 Show 打印 <
Prelude> :m + Text.Show.Functions
Prelude Text.Show.Functions> show(<)
"<function>"
// 枚举类型类
Prelude> [1..10]
[1,2,3,4,5,6,7,8,9,10]
......

image.png


上图不在灰色方框内的部分全部是类型类;

Haskell 给很多“类型”分成了“类型类”,归为一类的类型有着共同的属性,不同类型所归的类就称为类型类。


每个类型类下面都写了一些该类型类中预定义的函数,我们可以接着打印输出体验:

// fromInteger 是 Num 类型类下的函数,可以将一个一个的整数转为一个重载的数类型 a
Prelude> :t fromInteger
fromInteger :: Num a => Integer -> a


有时需要将一个整数转为复数类型或者比值类型,这时就可以使用它。

Prelude> :m Data.Ratio
Prelude Data.Ratio> fromInteger 5 :: Ratio Int
5 % 1


还有熟悉的向下取整方法:

Prelude> :t floor
floor :: (RealFrac a, Integral b) => a -> b
Prelude> floor(1.2)
1


类型类中定义了一些函数,如果定义了一个新的类型,只要这个类型实现了类型类中声明的函数这个类型就属于该类型类了;


小结🤖



入门第一篇,类型在程序语言中非常重要!


强类型:可以帮助我们检查错误、对程序进行抽象(函数式编程关键)、具有文档说明作用。


可以看出,Haskell 的严格定义类型和 javaScript 中还是有较大差异,一个强类型,一个弱类型~


强类型适合大型项目的维护,弱类型与动态性结合,开发简单,处理灵活;

Haskell 的类型类,以及类型类底下的各种函数,真的太好用了吧~ 不用理会类型转换,特别是像 js 中的隐式转换,真的太爽了~


在逐渐学习的过程中,不断提升强类型设计精髓的理解。

看到这里,点个赞吧~ 👍 掘文不易,还需鼓励~ 👏

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


相关文章
|
JavaScript 编译器
热爱函数式的你,句句纯正的 Haskell【表达式篇】
表达式是编程语言中最常用到的基础之一,本片让我们来看看在 Haskell 中表达式是怎样的?
热爱函数式的你,句句纯正的 Haskell【表达式篇】
|
JavaScript 编译器
热爱函数式的你,句句纯正的 Haskell【库函数篇】
本篇是笔记篇,介绍 Haskell 的强大的库函数,也可感受下与我们平常的 js 操作异同之处:
热爱函数式的你,句句纯正的 Haskell【库函数篇】
|
编译器
热爱函数式的你,句句纯正的 Haskell【函数篇】
Haskell 值与函数是统一的,函数只是需要其他参数输入的值。如果定义的是函数,那么这个函数的行为在运行过程中也是不会改变的,对于某一个特定的输入返回的结果总是确定的,这样的函数为纯函数。
|
Shell BI 测试技术
Haskell 编程入门
在过去的几个月里,学习Haskell让我觉得非常快乐,但是入门的过程并没有我原先想象的那么简单。我非常幸运地在一个正确的地方工作,并且因此能够在Facebook参加Bryan O'Sullivan的Haskell课程。在Try Haskell上玩了一段时间后,最终你就会想要在自己的电脑上安装GHC了。
184 0
Haskell 编程入门
|
存储 Java 程序员
C++ 开发者快速学习 Objective-C 语言核心语法
本文将讨论 Objective-C 语言的核心语法。这部分开始详述一些具体的语法。正如你期待的一样,涉及到了定义和类。
236 0
haskell简明入门(一)
本文的主要内容参考自《Haskell趣学指南》 1. What is Haskell?     以下内容引用自Haskell官网: Haskell是一个先进的,纯粹的函数式编程语言。一个典型的声明式地,静态类型的代码如下: primes = filterPrime [2.
1479 0
|
前端开发 JavaScript
JavaScript 编程精解 中文第三版 五、高阶函数
五、高阶函数 原文:Higher-Order Functions 译者:飞龙 协议:CC BY-NC-SA 4.
1555 0
|
安全 C语言
《Haskell函数式编程入门》—— 第1章,第1.6节本章小结
本节书摘来自异步社区《Haskell函数式编程入门》一书中的第1章,第1.6节本章小结,作者 张淞,更多章节内容可以访问云栖社区“异步社区”公众号查看
1518 0