标准库
Build Your Own Lisp · 第 15 章
为 Lisp 实现标准库
Chapter 15 · 标准库
内置函数
标准库概述
在本章中,我们将为我们的 Lisp 实现一个标准库。标准库是一组预定义的函数,它们提供了常用的功能,让用户可以更方便地编写程序。
我们将把标准库写成 Lisp 代码,然后在启动时加载它。这样做的好处是:
- 标准库可以用 Lisp 本身来编写,不需要修改 C 代码
- 用户可以查看和学习标准库的实现
- 标准库可以被扩展和修改
数学函数
我们将实现以下数学函数:
数学内置函数
+:加法-:减法*:乘法/:除法%:取模^:幂运算min:最小值max:最大值
这些函数已经在前面的章节中实现了。现在我们需要确保它们都被正确注册到环境中。
列表操作
列表是 Lisp 中最重要的数据结构之一。我们将实现以下列表操作:
列表内置函数
list:创建列表head:获取列表第一个元素tail:获取列表除第一个元素外的部分join:连接列表eval:求值列表cons:将元素添加到列表头部len:获取列表长度init:获取列表除最后一个元素外的部分last:获取列表最后一个元素
lval* builtin_list(lenv* e, lval* a) {
a->type = LVAL_QEXPR;
return a;
}
lval* builtin_head(lenv* e, lval* a) {
LASSERT_NUM("head", a, 1);
LASSERT_TYPE("head", a, 0, LVAL_QEXPR);
LASSERT_NOT_EMPTY("head", a, 0);
lval* v = lval_take(a, 0);
while (v->count > 1) { lval_del(lval_pop(v, 1)); }
return v;
}
lval* builtin_tail(lenv* e, lval* a) {
LASSERT_NUM("tail", a, 1);
LASSERT_TYPE("tail", a, 0, LVAL_QEXPR);
LASSERT_NOT_EMPTY("tail", a, 0);
lval* v = lval_take(a, 0);
lval_del(lval_pop(v, 0));
return v;
}
控制流
控制流函数用于控制程序的执行顺序:
控制流内置函数
if:条件分支while:循环do:顺序执行多个表达式
lval* builtin_while(lenv* e, lval* a) {
LASSERT_NUM("while", a, 2);
LASSERT_TYPE("while", a, 0, LVAL_QEXPR);
LASSERT_TYPE("while", a, 1, LVAL_QEXPR);
lval* cond = lval_pop(a, 0);
lval* body = lval_pop(a, 0);
lval_del(a);
while (1) {
lval* c = lval_eval(e, lval_copy(cond));
if (c->num == 0) {
lval_del(c);
break;
}
lval_del(c);
lval* x = lval_eval(e, lval_copy(body));
if (x->type == LVAL_ERR) {
lval_del(cond); lval_del(body);
return x;
}
lval_del(x);
}
lval_del(cond); lval_del(body);
return lval_sexpr();
}
复习速查
- 标准库:用 Lisp 编写的预定义函数集合
- 数学函数:
+、-、*、/、%、^ - 列表操作:
list、head、tail、join、cons - 控制流:
if、while、do