【Real World Haskell】读书笔记 2.Types and Functions【上】

       这几天多了些活儿,在这上面花费的时间少了很多。这一节打算分成两部分来写,上部分主要跟类型相关,下部分主要跟函数相关。另外,这一节关于编程语言特性的文字比较多,我在翻译的过程中进行了一些取舍,有些部分干脆直接跳过或者总结性地说一两句,有些部分在翻译的时候也不是很通顺,请见谅。


 

       这一节主要讲述Haskell的类型和函数,了解这两者在Haskell中的含义和用途。

为什么要关心类型?

       在我们深入Haskell的类型系统之前,我们来讨论到底为什么我们要关心类型,它们的作用是什么?

       在计算机最底层,计算机关心的是字节,几乎没有任何其他的数据结构。类型系统带给我们的就是抽象,可以给字节赋予含义。引用抽象的好处就是我们可以忽略底层细节,不需要了解具体是如何实现,使得编程更加容易被人理解。类型系统也是多样化的,不同的类型系统通常不会关注相同类型的问题,一种编程语言的类型系统会深刻地反映出我们用这种语言进行思维和编码的方式。Haskell的类型系统允许我们以非常抽象的层面来思维,并允许我们编写简洁、强大的程序。

 

Haskell的类型系统
强类型
       当我们说Haskell有一个强的类型系统时,我们的意思是类型系统保证了程序不能包含具体类型的错误。这些错误来源于尝试编写没有意义的表达式,比如使用一个整数作为函数。又如,如果一个函数希望处理整数,而我们向它传递一个字符串,Haskell编译器将会拒绝这样的事情发生。
       我们把遵守一种语言的类型规则的表达式称为well typed,不遵守这个类型规则的表达式称为ill typed,并且它将会导致类型错误。
       Haskell强类型的另一个方面体现在它不会自动地将一种类型强制转换为另一种类型。比如,一个函数声明的参数类型是float,在调用该函数时若指定的参数是int型,在C语言中编译器是会自动将int型转换为float型,但是Haskell在相同情况发生时会报编译错误,如果需要转换类型需要显式地调用转换函数。
       强类型有时会让编程更加困难。比如,在C语言中编写底层代码的一种经典方式是给一个字节数组,并把它们当作一种复杂的数据结构进行转换。这种方法十分高效,因为它不需要我们重新拷贝字节数组。Haskell的类型系统不允许这种转换发生。为了完成这种操作,我们需要做一些拷贝,这会消耗一些性能。
       强类型的最大好处就是它能在发生问题之前找到真正的bug。例如,在一种强类型语言中,当需要一个整型数时能防止我们意外地使用字符串类型。


静态类型
       拥有静态的类型系统意味着编译器在编译时(任何代码执行前)便知道每个值和表达式的类型。当我们试着用类型不匹配的表达式时,Haskell编译器或解释器将会检测到,并且在我们运行它之前提示错误信息。

       我们之前就见过这种错误。编译器提示表达式"false"的类型是[char]。&&操作符要求它的操作数是Bool类型,而它左边的操作数确实是Bool类型。因为"false"的实际类型不匹配要求的类型,于是编译器判断表达式类型错误。
       静态类型有时在编写一些有用代码时会很棘手。在像Python这类语言中,鸭子类型很普遍,当一个对象使用起来像另一个对象时,它可以替代这个对象。不幸的是,Haskell的类型分类系统以一种安全而方便的形式,提供了几乎所有动态类型的好处。Haskell对于动态类型编程有一定的支持,尽管在一种语言中完全实现这种概念并不是那么容易。
       Haskell强类型和动态类型的结合使得程序在运行时出现类型错误变成不可能。这意味着我们在开始就需要做点事情,它也减少了很多简单错误的出现,尽管它们很难被发现。一旦代码编译完成,Haskell比其他语言更有可能会正常运行。(这是在Haskell社区里老生常谈的)或许更现实的一种表述是Haskell代码通常很少有琐碎的bug。
       用动态类型语言编写的程序需要大量的测试集来保证简单的类型错误不会发生。测试集当然不可能完全覆盖整个程序。反而在进行一些平常的任务时,比如重构一个程序使它更加模块化,会带来新的类型错误,它们可能不会被测试集发现。
       在Haskell中编译器会为我们指出程序中出现的类型错误,这样在运行时程序是不会出现类型错误的。重构通常就是将代码重新布置,然后重新编译和整理一些次数,直到编译器告诉我们编译没有错误之后。
       一个能够帮助我们理解静态类型的实质类比就是拼图游戏。在Haskell中,如果一块形状不对,那么它不会拼进去。而在一种动态语言中,所有小块都是1x1的方形,它们总会拼进去,于是你不得不不停地通过测试检查结果是否正确。


类型推断
       最后,Haskell编译器会自动推断程序中几乎所有表达式的类型。这个过程被称作类型推断。Haskell允许我们显示声明任何值的类型,但是类型推断的出现意味着这基本算是多余的,不是我们应该做的事情。


我们期望从类型系统得到什么
       对于Haskell类型系统性能和优势的探索可以占用大量的篇幅。开始你可能会觉得Haskell的类型处理起来会是件繁琐的事情。比如,你期望能编写简单的代码,接着运行起来测试程序是否正确,这在Python或者Ruby当中是件显而易见的事情,但在Haskell中你首先必须要保证你的程序能够通过类型检查器的审查。为什么要坚持学习曲线?
       强类型和静态类型使得Haskell变得安全的同时,类型推导使得Haskell变得简明。Haskell语言是非常强大的,它比流行的静态类型语言更加安全,而且通常比动态类型语言更容易表达。
       修改类型错误最开始可能比使用动态语言耗费更多工作量,但这样看起来把你调试的工作提前了。编译器会告诉你代码中大多数逻辑错误,而不会在程序运行时出现错误。
       而且,由于Haskell能够判断表达式和函数的类型,你不用承受其他不够强大静态类型语言带来的“finger typing”负担。在其他编程语言中,类型系统是为编译器需求服务的,而在Haskell中,它是为你服务的。唯一的代价就是你不得不学习如何在它的体系下工作。


基本类型

  • Char值表示Unicode字符。
  • Bool值代表布尔逻辑值,包括True和False。
  • Int类型用来表示有符号、定长的整型数,长度同机器字长相同。
  • Integer值表示没有边界的有符号整数,它对比Int类型起来更耗费性能和空间,但Integer数值在进行计算时不容易溢出。
  • Double类型用来表示浮点数,宽度为64位。 

转载于:https://www.cnblogs.com/blacksword/archive/2012/12/26/2834452.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值