RealWorldHaskell中文版
本文档是 Real World Haskell 一书的简体中文翻译版本Real World haskel中文版关于以下人员参与了本文档的翻译工作:huangHaisheng, WuAlbertGuang Yang·| labyRinthJavan chengbladewangspectatortiancalamao除了进行翻译之外,本文档还在原书的基础上做了以下改进:修正原文正文和代码中的错误更新代码以符合最新的 Hasek规范在一些比较复杂的地方添加注释,帮助理解关注项目进度/反馈意见或建议/提交你的翻译贡献,请访问项目的 github页面。本文档的部分内容参考了 Albertlee的译本,在此对他表示感谢。版权本文档和原书一样,通过CC协议进行署名-非商业性使用授权。本文档使用看云构建Real World haskel中文版第一章:入门第一章:入门Haskel编程环境在本书的前面一些章节里,我们有时候会以限制性的、简单的形式来介绍一些概念。由于 Haskel是一本比较深的语言,所以一次性介绍某个主题的所有特性会令人难以接受。当基础巩固后,我们就会进行更加深入的学习。在 Haskel语言的众多实现中,有两个被广泛应用,Hugs和GHC。其中Hugs是一个解析器,主要用于教学。而GHC( GlasgowHaskellCompiler)更加注重实践,它编译成本地代码,支持并行执行,并带有更好的性能分析工具和调试工具。由于这些因素,在本书中我们将采用GHC。GHC主要有三个部分组成。ghc是生成快速本底代码的优化编译器。hcl是一个交互解析器和调试器。runge是个以脚本形式并不要首先编译)运行 Haske‖代码的程序Note我们如何称呼GHC的各个组件当我们讨论整个GHC系统时,我们称之为GHC。而如果要引用到某个特定的命令,我们会直接用其名字标识,比如ghe,ghci, runge在本书中,我们假定你在使用最新版6.8.2版本的GHC,这个版本是2007年发布的。大多数例子不要额外的修改也能在者的版本上运行。然而,我们建议使用最新版本。如果你是Ⅵ indows或者 MacOSX操作系统,你可以使用预编译的安装包快速上手。你可以从GHC下载页面找到合适的二进制包或者安装包。对于大多数的 Linux版本,BSD提供版和其他Unⅸ系列,你可以找到自定义的GHC二进制包。由于这些包要基于特性的环境编译,所以安装和使用显得更加容易。你可以在GHC的二进制发布包页面找到相关下载我们在附录A中提供了更多详细的信息介绍如何在各个流行平台上安装GHC初识解释器ghcighci程序是GHC的交互式解析器。它可以让用户输入 Haske表达式并对其求值,浏览模块以及调试代码。如果你熟悉 Python或是Ruby,那么ghc定程度上和 python,ib很像,这两者分别是 Python和Ruby的交互式解析器。本文档使用看云构建Real World haskel中文版The ghci command has a narrow focusWe typically can not copy some code out of a haskell source file and paste it into ghci. This does nothave a significant effect on debugging pieces of code, but it can initially be surprising if you are usedto, say, the interactive Python interpreter.在类Uniκ系统中,我们在she‖枧窗下运行ghi。而在 Windows系统下,你可以通过开始菜单找到它。比如,如果你在 WindowsXP下安装了GHC,你应该从”所有程序”,然后”GHC"下找到ghci。(参考附录A章节 Windows里的截图。)当我们运行ghc时,它会首先显示一个初始 banner,然后就显示提示符 Prelude>。下载例子展示的是Linux环境下的6.8.3版本。s ghoGhci,version6.8.3:http://www.haskellorg/ghc/:?forhelpLoading package base…. linking…donePrelude>提示符 Prelude标识一个很常用的库 Prelude已经被加载并可以使用。同样的,当加载了其他模块或是源文件时,它们也会在出现在提示符的位子Tip获取帮助信息在ghc提示符输入:?,则会显示详细的帮助信息。模块 Prelude有时候被称为“标准序幕”( the standardprelude),因为它的内容是基于 Haskell98标准定义的。通常简称它为“序幕”( theprelude)Note关于ghc的提示符提示符经常是随着模块的加载而变化。因此经常会变得很长以至在单行中没有太多可视区域用来输入。为了简单和一致起见,在本书中我们会用字符串‘ghi>'来替代ghc的默认提示符。你可以用ghc的 c setprompt来进行修改。Prelude>: set prompt" ghci>ghci>prelude模块中的类型,值和函数是默认直接可用的,在使用之前我们不需要额外的操作。然而如果需要其他模块中的一些定义,则需要使用ghc的 module方法预先加载。ghci> module Data Ratio本文档使用看云构建Real World haskel中文版现在我们就可以使用Data. Ratio模块中的功能了。这个模块提供了一些操作有理数的功能。基本交互:把ghci当作一个计算器除了能提供测试代码片段的交互功能外,ghci也可以被当作一个桌面计算器来使用。我们可以很容易的表示基本运算,同时随着对 Haske了解的深入,也可以表示更加复杂的运算。即使是以如此简单的方式来使用这个解析器,也可以帮助我们了解更多关于 Haske是如何工作的。基本算术运算我们可以马上开始输入一些表达式,看看ghc会怎么处理它们。基本的算术表达式类似于像C或是 Python这样的语言:用中缀表达式,即操作符在操作数之间ghci> 2+24ghci>31337*1013165037ghci>7.0/2.03.5用中缀表达式是为了书写方便:我们同样可以用前缀表达式,即操作符在操作数之前。在这种情况下,我们需要用括号将操作符括起来。ghci> 2+ 24ghci>(+)224上述的这些表达式暗示了一个概念, Haskel整数和浮点数类型。整数的大小是随意的。下面例子中的(^)表示了整数的乘方。ghi>313~1527112218957718876716220410905036741257算术奇事( quirk),负数的表示在如何表示数字方面 Haskel提供给我们一个特性:通常需要将负数写在括号内。当我们要表示不是最简单的表达式时,这个特性就开始发挥影响。我们先开始表示简单的负数ghci> -3上述例子中的-是一元表达式。换句话说,我们并不是写了一个数字“-3″;而是一个数字“3”,然后作用于操作符-。-是 Haskel中唯一的一元操作符,而且我们也不能将它和中缀运算符一起使用。本文档使用看云构建Real World haskel中文版ghci> 2+-3: 1: 0precedence parsing errorcannot mix(+)[infix 6] and prefix -[infix 6] in the same infix expression如果需要在一个中缀操作符附近使用一元操作符,则需要将-元操作符以及其操作数包含的括号內。ghci>2+(-3)ghci>3+(-(13*37)-478如此可以避免解析的不确定性。当在 Haske应用(app!y)一个函数时,我们先写函数名,然后随之其参数比如f3。如果我们不用括号括起一个负数,就会有非常明显的不同的方式理解f-3:它可以是“将函数f应用( apply)与数字3”,或者是“把变量f减去3”。大多数凊况下,我们可以省略表达式中的空格(“空”字符比如空格或制表符tab), Haske‖也同样能正确的解析。但并不是所有的情况。ghci> 2*3下面的例子和上面有问题的负数的例子很像,然而它的错误信息并不一样。ghci> 2*-3: 1: 1: Not in scope:*这里 Haskel把-理解成单个的操作符。 Haske∥允许用户自定义新的操作符(这个主题我们随后会讲到),但是我们曾定义过。ghi>2*(-3)相比较其他的编程语言,这种对于负数不太一样的行为可能会很些怪异,然后它是一种合理的折中方式。Haskel!许用户在仼何时候自定义新的操作符。这是一个并不深奥的语言特性,我们会在以后的章节中看到许多用户定义的操作符。语言的设计者们为了拥有这个表达式强项而接受了这个有一点累赘的负数表达语法。布尔逻辑,运算符以及值比较Haskel中表示布尔逻辑的值有这么两个:True和Fase。名字中的大写很重要。作用于布尔值得操作符类本文档使用看云构建Real World haskel中文版似于C语言的情况:(&&)表示“逻辑与”,()表示“逻辑或”ghci> true & FalseFalseghci> False‖TrueTrue有些编程语言中会定义数字0和 False同义,但是在 Haskel中并没有这么定义,同样的,也 Haskell没有定义非0的值为Trueghci> true &&1: 1: 8No instance for(Num bool)arising from the literal 1 ' at 1: 8Possible fix: add an instance declaration for (num bool)In the second argument of (&8), namely 1In the expression: True & 1In the definition of it'. it true & 1我们再一次的遇到了很有前瞻性的错误。简单来说,错误信息告诉我们布尔类型,Bool,不是数字类型,Num的一个成员。错误信息有些长,这是因为gh会定位出错的具体位置,并目给出了也许能解决问题的修改提示。错误信息详细分析如下。“ No instance for( Num boo)”告诉我们ghc尝试解析数字1为Boo类型但是失败。“ arising from the litera1”表示是由于使用了数字1而引发了问题。" In the definition of it"”引用了一个ghc的快捷方式。我们会在后面提到。Ti遇到错误信息不要胆怯这里我们提到了很重要的一点,而且在本书的前面一些章节中我们会重复提到。如果你碰到一些你从来没遇到过的问题和错误信息,别担心 panIc。刚开始的时候,你所要的做的仅仅是找出足够的信息来帮助解决问题。随着你经验的积累,你会发现错误信息中的一部分其实很容易理解,并不会像刚开始时那么晦涩难懂。各种错误信息都有一个囯的:通过提前的一些调试,帮助我们在真正运行程序之前能书写出正确的代码。如果你曾使用过其它更加宽松( permissive)的语言,这种方式可能会有些震惊( shock所以,拿出你的耐心来。 Haskel中大多数比较操作符和C语言以及受C语言影响的语言类似。ghci> 1== 1Trueghci> 2<3Trueghci>4>=399True有一个操作符和C语言的相应的不一样,“不等于”。C语言中是用!=表示的,而 Haskel是用/=表示的,它看上去很像数学中的≠。本文档使用看云构建Real World haskel中文版另外,类C的语言中通常用!表示逻辑非的操作,而 Haskel中用函数not。ghci> not trueFalse运算符优先级以及结合性类似于代数或是使用中缀操作符的编程语言, Haskel也有操作符优先级的概念。我们可以使用括号将部分表达显示的组合在一起,同时操作符优先级允许省略掉一些括号。比如乘法比加法优先级高,因此以下两个表达式效果是一样的。ghci>1+(4*4)17ghci>1+4*417Haskel给每个操作符一个数值型的优先级值,从1表示最低优先级,到9表示最高优先级。高优先级的操作符先于低优先级的操作符被应用( apply)。在ghi中我们可以用命令nfo来查看某个操作符的优先级。ghci> info(+)class(eq a, Show a)=> Num a where(+)∷a->a->aDefined in ghc Numinfix 6+gnc> InToclass(eq a, Show a)=> Num a where()∷a->a->aDefined in ghc numinfix 7*这里我们需要找的信息是“inf×6+”,表示(+)的优先级是6。(其他信息我们稍后介绍。)"infx7"表示)的优先级为7。由于(比(+优先级高,所以我们看到为什么1+44和1+(44)值相同而不是(1+44。Haskell也定义了操作符的结合性( associatIvity)。它决定了当一个表达式中多次出现某个操作符时是否是从左到右求值。(+)和()都是左结合,在上述的ghc输出结果中以inf表示。一个右结合的操作符会以infix表Thci> info ()(): : (Num a, Integral b)=> a->b->a--Defined in GHC. Reainfix A本文档使用看云构建Real World haskel中文版优先级和结合性规则的组合通常称之为固定性(Xty规则。未定义的变量以及定义变量Haske的标准库 prelude定义了至少个大家熟知的数学常量。ghci> pi3.141592653589793然后我们很快就会发现它对数学常量的覆盖并不是很广泛。让我们来看下Euer数,e。ghci> e: 1: 0: Not in scope: e啊哈,看上去我们必须得自己定义。不要担心错误信息以上" not in the scope”的错误信息看上去有点令人畏惧的。别担心,它所要表达的只是没有用e这个名字定义过变量。使用gh的let构造器( contruct,我们可以定义一个临时变量eghci> let e exp 1这是指数函数exp的一个应用,也是如何调用一个 Haskell函数的第一个例子。像 Python这些语言,函数的参数是位于括号内的,但 Haskel不要那样既然e已经定义好了,我们就可以在数学表达式中使用它。我们之前用到的乘方操作符(^)是对于整数的。如果要用浮点数作为指数,则需要操作符(*)。ghci>(e * pi)-pi1999909997918947Note这是ghc的特殊语法hdi中let的语法和常规的“ top level"的 Haskel序的使用不太一样。我们会在章节“初识类型”里看到常规的语法形式。处理优先级以及结合性规则有时候最好显式地加入一些括号,即使 Haskel!允许省略。它们会帮助将来的读者,包括我们自己,更好的本文档使用看云构建
用户评论