codecamp

第一章 Haskell简介

  • 关于这个教程
  • 那么,haskell是啥?
  • 你需要...

关于这个教程

欢迎来到 haskell 趣学指南!阅读此文表明你正要学 haskell。很好,来对地方了,先容我简单介绍一下这个教程。

编写这个教程,一方面是为了巩固我自己对 haskell 的理解,另一方面也是希望能够分享我的经验,给初学者提供一定帮助。网络上已经有无数 Haskell 的教学文档,在我学习的时候就曾参阅过许多教程与文章,它们讲解问题的思路各不相同,综合的阅读使得我最终能够整理起知识的碎片并正确地理解。所以说,编写这个教程也是创造另一个学习资源的尝试,给读者增加一个选择的余地。

本教程主要是面向已经有命令式编程经验(C, C++, Java, Python …) 、却未曾接触过函数式编程 (Haskell, ML, OCaml …)的读者。还没有编程基础?没关系,像你这样的聪明小伙一定能够学会 haskell!

若在学习中遇到什么地方不明白,freenode IRC 上的 #Haskell 频道是提问的绝佳去处。那儿的人们友善,耐心且照顾新人。

在我掌握 haskell 之前的学习曾经失败过两次,它看起来太不可思议,难以理解。不过随后突然灵光一闪,马上就开窍了,往后的学习也就变得游刃有余。我想说的就是:haskell 很棒,如果你喜欢编程,那就得好好学学--尽管在咋一看它可能会显得很别扭--它迫使你换个脑筋思考,很有趣!

那么,haskell 是什么?

haskell 是一门纯函数式编程语言。在命令式语言中执行操作需要给电脑安排一组命令,随着命令的执行,状态就会随之发生改变。例如你给变量 a 赋值为 5,而随后做了其它一些事情之后 a 就可能变成的其它值。有控制流程,你就可以重复执行操作。然而在函数式编程语言中,你不是像命令式语言那样命令电脑“要做什么”,而是通过用函数来描述出问题“是什么”,如“阶乘是指从1到某数间所有数字的乘积”。变量一旦赋值,就不可以更改了,你已经说了 a 就是 5,就不能再另说 a 是别的什么数。做人不能食言,对不?所以说,函数式编程语言中的函数能做的唯一事情就是求值,因而没有副作用。一开始会觉得这很受限,不过好处也正源于此:若以同样的参数调用同一函数两次,得到的结果总是相同。这被称作“引用透明”。如此一来编译器就可以理解程序的行为,你也很容易就能验证一个函数的正确性,继而可以将一些简单的函数组合成更复杂的函数。

haskell 是惰性的。也就是说若非特殊指明,函数在真正需要结果以前不会被求值。再加上引用透明,你就可以把程序仅看作是数据的一系列变形。如此一来就有了很多有趣的特性,如无限长度的数据结构。假设你有一个 List:xs = [1,2,3,4,5,6,7,8],还有一个函数doubleMe,它可以将一个List中的所有元素都乘以二,返回一个新的List。若是在命令式语言中,把一个 List 乘以 8,执行doubleMe(doubleMe(doubleMe(xs))),得遍历三遍 xs 才会得到结果。而在惰性语言中,调用 doubleMe 时并不会立即求值,它会说“嗯嗯,待会儿再做!”。不过一旦要看结果,第一个 doubleMe 就会对第二个说“给我结果,快!”第二个 doubleMe 就会把同样的话传给第三个 doubleMe,第三个doubleMe只能将 1 乘以 2 得 2 后交给第二个,第二个再乘以 2 得 4 交给第一个,最终得到第一个元素 8。也就是说,这一切只需要遍历一次list即可,而且仅在你真正需要结果时才会执行。惰性语言中的计算只是一组初始数据和变换公式。

haskell 是静态类型的。当你编译程序时,编译器需要明确哪个是数字,哪个是字符串。这就意味着很大一部分错误都可以在编译时被发现,若试图将一个数字和字符串相加,编译器就会报错。haskell 拥有一套强大的类型系统,支持自动类型推导。这一来你就不需要在每段代码上都标明它的类型,像计算 a=5+4,你就不需另告诉编译器“a 是一个数值”,它可以自己推导出来。类型推导可以让你的程序更加简练。假设有个二元函数是将两个数值相加,你就无需声明其类型,这个函数可以对一切可以相加的值进行计算。

haskell 采纳了很多高级概念,因而它的代码优雅且简练。与同层次的命令式语言相比,haskell 的代码往往会更短,更短就意味着更容易理解,bug 也就更少。

haskell 的研发工作始于 1987 年,当时是一个学会的精英分子(很多 PhD 哦)聚到一块儿,商量着要设计一门牛 X 的语言。03 年,《 Haskell Report 》发布,标志着稳定版本的最终确定。

你需要...

一个编辑器和一个编译器。你可能已经安装了最喜欢的编辑器,在此不加赘述。如今最常用的 haskell 编译器是 GHC 和 hugs,在本教程中我们将使用 ghc。安装的细节就不消多说了,在 windows 下只要下载一个 installer 然后一路next最后重启一下(貌似不需要重启,译者注)即可;在基于 debain 的 linux 系统下一个

apt-get install ghc6 libghc6-mtl-dev

看着玩就是了;我没 mac 电脑,不过听说你如果安装了 macPort,就可以通过

sudo port install ghc

来获得 ghc。嗯,应该可以用那古怪的单键鼠标搞 haskell 吧,我拿不准。

GHC 既可以解释执行 haskell 脚本(通常是以 .hs 作为后缀),也可以编译。它还有个交互模式,你可以在里面调用脚本里定义的函数,即时得到结果。 对于学习而言,这可比每次修改都编译执行要方便的多。想进入交互模式,只要打开控制台输入 ghci 即可。假设你在 myfunctions.hs 里定义了一些函数,在 ghci 中输入:l myfunctions.hs}载后就可以调用了。一旦修改了这个 .hs 文件的内容,再次执行:l myfunctions.hs或者与之等价的 :r,都可以重新装载该文件。我本人通常就是在 .hs 文件中定义几个函数,再到 ghci ,调试,再修改再装载。这也正是我们往后的基本流程。


第二章 Haskell入门
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }