Chinaunix首页 | 论坛 | 博客
  • 博客访问: 467060
  • 博文数量: 55
  • 博客积分: 2603
  • 博客等级: 少校
  • 技术积分: 750
  • 用 户 组: 普通用户
  • 注册时间: 2006-12-31 02:30
文章分类

全部博文(55)

文章存档

2011年(1)

2010年(22)

2009年(17)

2008年(15)

我的朋友

分类:

2008-12-16 21:55:17

上一节的时候我们讨论到了用附加的解释器组件扩展功能的方法。这一次我们再加些料。
首先,我们定义出Scheme语言中的一些类型:


Haskell语言:

事 实上,Haskell里一切都可以看作是函数,data也不例外。千万不要拿这个东西去随便对应你以前见过的其它叫data的东西。事实上Haskell 里的Type、Class、Instance和Data跟OO语言里的概念都完全不是一回事儿。如果你有学过近世代数,可以去看看上节里推荐的T1的那篇 Monad教程。



这里,使用data,我们定义了 LispVal 可能的几种类型:



  • Atom 是一个文本,它表示一个原子命名
  • 若干 LispVal 的序列成为一个 List (注意 List 也是一种 data Lispval,所以这是一个递归的定义)
  • . 联接列表和一个 LispVal 值,组成一个 DottedList
  • Number 存储整数
  • String 存储字符串
  • Bool 存储逻辑值




因为Haskell的类型和构造器取自不同的命名空间,所以这里我们定义了与系统类型相同的String、Bool之类的类型,也不会靠成什么问题。类型和构造器都是PASCAL命名。


现在编写几个解释器函数。首先是字符串。字符串是一对双引号标记,包含若干文。



Haskell语言:

这 儿又出来一新的妖招:我们没用 >>,而是用了一个do。这是为了可以取到引号之间的值,这里我们用了char和many两个解析工具。按作者的解释,通常不需要取得 action返回值的时候(比如为了组合它们生成新的monad),使用>>,而需要取值并用于下一个action的时候,用 >>= 或 do-notation。


取值完成以后,我们将其 return 为一个 LispVal 。抽象数据类型中的每个构造器也同样可以看作是一个函数:返回一个该类型的值。函数进行参数的式匹配的时候,也可以根据data来匹配。


内 置函数 return 可以把我们的 LispVal 提升为一个Parser monad。每一行do代码虽然都要求是同一个类型,但是但是我们的字符串解析函数只是返回了一个 LispVal,这时候就靠 return 帮我们搞定这个类型封装啦。这样,整个 parseString action 就成为了一个 Parser LispVal。


$只 是括号的简写 return $ String x 等同于 return (String x),这个在Haskell的语法教程中都会有介绍。不过这里有特别提出,$是一个操作符,所以你能对一个函数做什么,就能对它做什么,传递、局部化等 等。在这里,它相当于一个 apply。

Atom 就是一个原子语素,一个字母或符号,跟随若干数值或字母、符号之类的:


Haskell语言:

这里出现了一个新的 Pasec combinator,选择运算符 <|>。它尝试第一个parser,失败就尝试第二个。哪个成功就返回哪个parser的值。

读取语素的第一个字符以及其余部分后,我们需要把它们合在一起。let语法定义了一个atom变量,我们使用联接符:把它们联起来。如果不用:,还可以用 [first] ++ rest。

case是基本语句,语法书都讲得很明白,这里不多讨论了。

Bloger真是神奇,动不动就把代码搞乱了,这边我也不贴了(CU居然没有Haskell支持,怨念),大家点链接进去看源码吧。
阅读(949) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~