索引
代码
编译器的设计和实现大量参考了 @Zinc 和Caml Light 0.75,因此取名Caml Featherweight了……实现方面更接近于 @Zinc ,Caml Light有些晦涩复杂的地方我换成自己乱想的实现了。
tl;dr的话可以直接读源码:https://github.com/MaskRay/CamlFeatherweight
完成度
介绍
ML是个一门通用的函数式编程语言,有如下一些特点:
- 采用call-by-value的求值策略,允许副作用和imperative programming。
- 使用垃圾收集。
- 支持first-class
function,函数可以像
int
、string
那样的值一样自由传递、创建。 - 实现了静态类型检查,并能自动推导类型,无需C中的类型注解。
- 提供了immutable programming的良好支持。
- 参数多态,提供了一些通用编程支持,类似于Java中的generic。
- 支持代数数据类型和模式匹配以处理复杂的数据结构。
本项目是@Zinc 提到的Zinc实验的一个实现,并大量参考了Caml Light 0.75的源码,实现了ML方言Caml的一个变体,以上提到的特性均已使用,在某些细节语法方面有省略和改动。
项目采用的Caml语言变体
内置类型
基本类型:
bool
,如true
、false
char
,如’a’
、’\n’
int
,如12
、0x0e
float
,如3.0
、2e-5
string
,如hello
、world
语言内置了一些类型构造器。
’a option
,如None
、Some (4,true,7,’a’)
操作符
=
,类型为’a -> ’a -> bool
<>
,类型为’a -> ’a -> bool
==
,类型为’a -> ’a -> bool
!=
,类型为’a -> ’a -> bool
<
,类型为’a -> ’a -> bool
<=
,类型为’a -> ’a -> bool
>
,类型为’a -> ’a -> bool
>=
,类型为’a -> ’a -> bool
int
类型支持的额外操作符:+
,-
,*
,/
,mod
,分别表示加、减、乘、除、和模运算,类型均为int -> int -> int
。
float
类型支持的额外操作符:+.
,-.
,*.
,/.
,即加减乘除,类型均为float -> float -> float
。
元组
元组是几种类型的复合,可以看成几种不同类型的有序集合。元组的各个成分用逗号分割,外面套圆括号,比如:
1 | # let a_tuple = (3,"three");; |
某些地方可以省略圆括号。
可以用模式匹配抽取元组的各个成分:
1 | # let (x,y) = a_tuple;; |
列表
元组可以把固定数目的不同元组聚合在一起,列表则可以表示相同类型的任意数目元素,语言提供的表示列表字面量的语法,如表示空列表的[]
,带有两个元素的列表[3; 4]
。
列表可以看成是一个单链表,单个节点可以为空([]
),或者包含一个元素和一个指向后继节点(对应的构造器为::
,比如:3::[]
)。::
构造器是一个操作符,是右结合的,之前提到的[3; 4]
可以看作3::4::[]
的语法糖。
数组
数组类似于列表,可以表示相同类型的任意数目元素,并提供了随机访问的功能:
1 | let a = [|3; 4; 7|] |
访问数组中的一个元素:
1 | a.(3) |
修改数组中的一个元素:
1 | a.(3) <- 'a' |
option
option
代表可能缺失的值,比如:
1 | let divide x y = |
函数
接受一个参数,返回参数加一的函数如下:
1 | let plus_one x = x + 1 |
和类C语言不同,函数名和参数间用空格分割,并且函数体前使用=
,因为ML中没有像C那样区分语句和表达式。
如果要定义多参数的函数,参数间也用空格分割:
1 | let sum_of_three x y z = x + y + z |
函数允许自递归,这时需要使用let rec
:
1 | let rec fib n = |
如果要定义互递归的函数,必须在一个let rec
中同时定义各个函数,它们之间用and
分割:
1 | let rec is_even x = |
代数数据类型和模式匹配
1 | type t = Zero | One of int | Two of char * int |
上面定义了一个类型t
,它有三个构造器:Zero
、One
和Two
,接受不同的参数。
模式匹配和代数数据类型配套使用,可以抽取构造器的参数:
1 | match a with |
模式匹配也可用于int
、string
等基本类型。_
是通配符,可以匹配任意值:
1 | match s with |
模式匹配也可用于复杂的类型,各分支中以以小写字母开头的表示符表示变量,可以匹配任意值,从而可以在->
后的表达式中引用:
1 | match s, 'a', 3+2 with |
异常
异常提供了一种中断当前的计算,报告错误,捕获错误的机制。
除数为零时会触发Division_by_zero
异常,下面的程序捕获了该异常并输出12:
1 | try |
如果模式匹配失败,则会产生Match_failure
异常:
1 | output_int (try |
try
实质上形成了一个动态作用域,如果最近的try
无法捕获的话,异常会交给外层的try
:
1 | output_int (try |
工具链使用说明
在项目目录下执行make
生成字节码编译器camlfwc
、字节码解释器camlfwrun
、字节码查看器camlfwod
。
编译并链接源文件得到可执行的字节码文件:
1 | % ./camlfwc -v /tmp/a.ml -o /tmp/a.out |
使用camlfwrun
执行:
1 | % ./camlfwrun /tmp/a.out |
camlfwod
可以显示目标文件或字节码可执行文件的指令列表。
1 | % ./camlfwod /tmp/a.zo |