Skip to content

语法

前言 ​

元语(meta-lisp)使用符号算式(S-expression)语法。

  • 模块顶层由语句(statement)组成。
  • 语句内由算式(expression)组成。

下面分组介绍 meta-lisp 的所有语法。

目录 ​

注释 ​

行注释 ​

注释以 ; 开头,直到行尾。

在写行注释的时候 lisp 程序员通常写两个 ;;。

meta-lisp
;; 这是一条注释
(定义 数 42) ;; 行尾注释

(@注释) ​

meta-lisp
(@注释 <符号算式> ...)

(@注释) 在编译时被忽略,其算式求值为 空值。

meta-lisp
(@注释 (函 (<形参> ...)
            <函数体>))
(@注释 (若 <条件> <真分支> <假分支>))
(@注释 foo bar)

@注释 被解析器识别为语法关键字,其内容是字面符号算式,不会被求值。

字面量 ​

原子 ​

整数由数字组成,可选负号。

meta-lisp
42
-1
0

浮点数带小数点。

meta-lisp
3.14
-2.5

文本用双引号包裹。

meta-lisp
"hello"
""

符号用单引号开头,后面跟名字。

meta-lisp
'foo
'bar

真假值用 真 和 假,它们不是字面量,而是绑定了真假值的变量。

空值用 空值,它也不是字面量,而是绑定了空值的变量。

(@列表) ​

meta-lisp
(@列表 <算式> ...)

创建列表。

meta-lisp
(@列表 1 2 3)
(@列表 "a" "b" "c")

增加 @ 前缀,是为了避免占用 列表 这个变量名。

(@集合) ​

meta-lisp
(@集合 <算式> ...)

创建集合。

meta-lisp
(@集合 1 2 3)

(@散列) ​

meta-lisp
(@散列 <键> <值> ...)

创建散列表。

meta-lisp
(@散列 'a 1 'b 2)
(@散列 "a" 1 "b" 2)

(@文本) ​

meta-lisp
(@文本 <算式> ...)

将多个文本算式拼接成一个文本。

meta-lisp
(@文本 "hello" " " "world")
(@文本 "(" 数 ")")
(@文本)

上面的例子等价于:

meta-lisp
(文本拼接 (@列表 "hello" " " "world"))
(文本拼接 (@列表 "(" 数 ")"))
(文本拼接 (@列表))

(@引用) ​

meta-lisp
'<符号算式>
(@引用 <符号算式>)

创建符号或原子列表。

meta-lisp
'(a b c)         ;; => (@list 'a 'b 'c)
'(1 2 3)         ;; => (@list 1 2 3)

等价于:

meta-lisp
(@引用 (a b c))  ;; => (@list 'a 'b 'c)
(@引用 (1 2 3))  ;; => (@list 1 2 3)

(@符号算式) ​

meta-lisp
(@符号算式 <符号算式>)

将符号算式转化为 符号算式型 类型的值,保留每个子节点的源代码位置信息。

符号算式型 类型的定义:

meta-lisp
(定义枚举 符号算式型
  (符号符号算式 (内容 符号型) (位置 源码位置型))
  (文本符号算式 (内容 文本型) (位置 源码位置型))
  (整数符号算式 (内容 整数型) (位置 源码位置型))
  (浮点符号算式 (内容 浮点型) (位置 源码位置型))
  (列表符号算式 (元素 (列表型 符号算式型)) (位置 源码位置型)))

使用示例:

meta-lisp
(@符号算式 foo)           ;; => (符号符号算式 'foo <位置>)
(@符号算式 (a b c))       ;; => (列表符号算式
                      ;;      (列表 (符号符号算式 'a) (符号符号算式 'b) (符号符号算式 'c))
                      ;;      <位置>)

变量 ​

(定义) ​

meta-lisp
(定义 <名字> <算式>)

定义模块级变量。

meta-lisp
(定义 答案 42)
(定义 问候 "hello")

变量 ​

变量引用一个已绑定的名字。

名字由字母、数字和 - 等字符组成。

meta-lisp
数
阶乘
列表长度
列表为空

限定变量 ​

<模块名>/<名字> 引用其他模块中的名字。

meta-lisp
内置/列表长度
内置/列表为空

限定名不需要先 (导入),可以直接使用。 (导入) 是专门用来取消 <模块名> 前缀的。

函数 ​

函数作用 ​

meta-lisp
(<目标> <参数> ...)

函数作用是最重要的语法。

如果符号算式的第一个位置不是语法关键词,就被认为是函数作用。

第一个位置是函数,其余是参数。

先求值函数位置的算式, 然后求值所有参数位置的算式, 然后进行函数作用。

meta-lisp
(整数加 1 2)
(打印行 "hello")
((函 (数) 数) 1)

当函数作用的参数个数不足时,会形成部分作用(通过柯里化实现)。

meta-lisp
((整数加 1) 2)

等价于:

meta-lisp
(整数加 1 2)

并且 (整数加 1) 可以作为值传递给函数,或者作为结果返回。

meta-lisp
(定义 加一
  (整数加 1))

等价于:

meta-lisp
(定义 (加一 数)
  (整数加 1 数))

(函) ​

meta-lisp
(函 (<形参> ...)
  <函数体>)

创建匿名函数。

(<形参> ...) 是形式参数列表, <函数体> 是一个或多个算式。 当函数被作用时,实际参数被绑定到形式参数,然后求值 <函数体>。

meta-lisp
(函 (数) (整数加 数 1))
((函 (数) (整数加 数 1)) 2)  ;; => 3

多个参数:

meta-lisp
(函 (甲 乙)
  (整数加 甲 乙))

等价于:

meta-lisp
(函 (甲)
  (函 (乙)
    (整数加 甲 乙)))

(定义) ​

meta-lisp
(定义 (<名字> <形参> ...)
  <函数体>)

定义函数。

定义函数等价于定义值为 lambda 的变量。

meta-lisp
(定义 (加一 数)
  (整数加 1 数))

等价于:

meta-lisp
(定义 加一
  (函 (数)
    (整数加 1 数)))

函数体 <函数体> 可以是多个算式:

meta-lisp
(定义 (函数 甲)
  (令 ((乙 (整数加 甲 1)))
    (整数乘 乙 2)))

类型 ​

原子类型 ​

类型说明例子
整数型整数42 -1
浮点型浮点数3.14 -2.5
文本型文本"hello"
符号型符号'foo
真假型真假值真 假
空值型空值空值
文件型文件(打开输入文件 "abc.txt")
类型型类型整数型
结森型结森值(解析结森 "42")
符号算式型带源码位置的符号算式(@符号算式 42)
源码位置型源码位置(作源码位置 "test" ...)
源码区间型源码区间(作源码区间 ...)
源码坐标型源码坐标(作源码坐标 0 0 0)

容器类型 ​

类型说明例子
(列表型 甲)元素类型为 甲 的不可变列表(@列表 1 2 3)
(数组型 甲)元素类型为 甲 的可变数组(@数组 1 2 3)
(集合型 甲)元素类型为 甲 的集合(@集合 1 2 3)
(散列型 甲 乙)键为 甲 值为 乙 的散列表(@散列 "a" 1)
(序对型 甲 乙)前项类型为 甲、后项类型为 乙 的序对(作序对 1 "a")
(或有型 甲)可能存在类型为 甲 的值的或有值(有 42)
(匣子型 甲)存放类型为 甲 的值的可变匣子(作匣子)

(->) ​

meta-lisp
(-> <参数类型> ... <返回类型>)

函数类型。

接收 <参数类型> 参数,返回 <返回类型>。

例如:

meta-lisp
(-> 整数型 整数型)
(-> 整数型 整数型 整数型)
(-> 文本型 真假型)

(声明) ​

meta-lisp
(声明 <名字> <类型>)

声称一个名字的类型。

编译器会从 (定义) 的 <函数体> 推导出类型, 然后检查是否与 (声明) 的类型一致。

meta-lisp
(声明 加一 (-> 整数型 整数型))
(定义 (加一 数) (整数加 数 1))

(声明 答案 整数型)
(定义 答案 42)

(承认) ​

meta-lisp
(承认 <名字> <类型>)

承认名字的类型。

与 (声明) 类似,但是编译器不会检查 (定义) 的 <函数体>。

meta-lisp
(承认 作点 (-> 浮点型 浮点型 点型))
(定义 (作点 甲 乙)
  (@列表 '作点 甲 乙))

(型例) ​

meta-lisp
(型例 <类型> <算式>)

给出类型,以及属于这个类型的实例。

编译器会检查实例的类型是否匹配。 可用于澄清代码意图。

meta-lisp
(型例 整数型 42)
(型例 (-> 整数型 整数型)
  (函 (数)
    (整数加 数 1)))

(泛型) ​

meta-lisp
(泛型 (<类型参数> ...)
  <类型>)

包含类型变量的类型。

类型变量通常用天干(甲、乙、丙……)表示,在 <类型> 中可以被引用。 用于 声明 中声称泛型函数。

meta-lisp
(声明 恒等函数 (泛型 (甲) (-> 甲 甲)))

(声明 首 (泛型 (甲) (-> (列表型 甲) 甲)))
(声明 余 (泛型 (甲) (-> (列表型 甲) (列表型 甲))))
(声明 添 (泛型 (甲) (-> 甲 (列表型 甲) (列表型 甲))))

(定义类型) ​

meta-lisp
(定义类型 <类型名>
  <函数体>)

(定义类型 (<类型名> <类型参数> ...)
  <函数体>)

定义一个新的类型。<类型名> 成为类型构造器,<函数体> 是一个求值为类型的算式。 带类型参数时,参数可以在 <函数体> 中被引用。

例如:

meta-lisp
(定义类型 (非空列表型 甲)
  (序对型 甲 (列表型 甲)))

使用举例:

meta-lisp
(型例 (非空列表型 整数型) (作序对 1 (@列表 2 3)))

条件 ​

(若) ​

meta-lisp
(若 <条件>
  <真分支>
  <假分支>)

条件分支。

<条件> 被求值。 如果为真,求值 <真分支> 并返回。 否则求值 <假分支> 并返回。

meta-lisp
(定义 (绝对值 数)
  (若 (整数小于 数 0)
    (整数负 数)
    数))

(当) ​

meta-lisp
(当 <条件>
  <函数体>)

条件为真时执行,用于副作用。

<条件> 为真时求值 <函数体>,否则跳过。 <函数体> 中可以写多个算式。 (当) 算式的返回值总是 空值。

meta-lisp
(当 调试
  (打印 "debug mode")
  (打印行 ""))

(除非) ​

meta-lisp
(除非 <条件>
  <函数体>)

条件为假时执行,用于副作用。

<条件> 为假时求值 <函数体>,否则跳过。 <函数体> 中可以写多个算式。 (除非) 算式的返回值总是 空值。

meta-lisp
(除非 (相等 数 0)
  (打印 (整数除 1 数))
  (打印行 ""))

(若则) ​

meta-lisp
(若则
  (<问> <答>)
  ...)

多分支条件。

依次求值每个 <问>。 第一个为真的分支的 <答> 被求值并返回。 末尾的 <问> 可以写 否则 作为默认分支。

meta-lisp
(定义 (分类 数)
  (若则
   ((整数为正 数) "positive")
   ((整数为负 数) "negative")
   (否则 "zero")))

(且) ​

meta-lisp
(且 <算式> ...)

短路与。

从左到右求值。遇到第一个假值就停止并返回该值。全真时返回最后一个值。

meta-lisp
(且 (为整数 数) (整数为正 数))

零个参数时返回 真。

(或) ​

meta-lisp
(或 <算式> ...)

短路或。

从左到右求值。遇到第一个真值就停止并返回该值。全假时返回最后一个值。

meta-lisp
(或 (相等 数 0) (相等 数 1))

零个参数时返回 假。

顺序与绑定 ​

(循序) ​

meta-lisp
(循序 <函数体>)

顺序执行。

<函数体> 可以是多个算式 <算式> ..., 依次求值,返回最后一个算式的值。 前面的算式通常是为了副作用。

meta-lisp
(循序
  (打印行 "step 1")
  (打印行 "step 2")
  42)  ;; => 42

(函) 和 (定义) 中的 <函数体> 函数体, 都类似于 (循序) 的 <函数体>。

meta-lisp
(定义 (函数 甲)
  (令 ((乙 (整数加 甲 1)))
    (整数乘 乙 2)))

(令) ​

meta-lisp
(令 ((<名字> <算式>)
      ...)
  <函数体>)

顺序局部变量绑定。

每个 <算式> 可以引用前面绑定的名字。

meta-lisp
(令 ((数 1))
  (整数加 数 1))  ;; => 2

(令 ((甲 1)
      (乙 2))
  (整数加 甲 乙))  ;; => 3

(令 ((甲 1)
      (乙 (整数加 甲 1)))
  (整数加 甲 乙))  ;; => 3

(递归令) ​

meta-lisp
(递归令 ((<名字> <算式>)
         ...)
  <函数体>)

类似 (令),但是允许递归与互相递归。

所有 <算式> 可以引用所有 <名字>。

互相递归的例子:

meta-lisp
(递归令 ((为偶数
          (函 (数)
            (若 (相等 数 0)
              真
              (为奇数 (整数减 数 1)))))
         (为奇数
          (函 (数)
            (若 (相等 数 0)
              假
              (为偶数 (整数减 数 1))))))
  (断言 (为偶数 4)))

顺序依赖的例子:

meta-lisp
(递归令 ((a 1)
         (b (整数加 a 1)))
  b)  ;; => 2

局部 (定义) ​

meta-lisp
(定义 (<名字> <形参> ...) <函数体>)
(定义 <名字> <算式>)

<函数体> 中的局部可递归变量绑定。

允许 (定义) 在 <函数体> 中使用。 用来代替嵌套的 (递归令),以减少缩进。

互相递归的例子(与 (递归令) 的例子等价):

meta-lisp
(循序
  (定义 (为偶数 数)
    (若 (相等 数 0)
      真
      (为奇数 (整数减 数 1))))
  (定义 (为奇数 数)
    (若 (相等 数 0)
      假
      (为偶数 (整数减 数 1))))
  (为偶数 4))

顺序依赖的例子:

meta-lisp
(循序
  (定义 a 1)
  (定义 b (整数加 a 1))
  b)  ;; => 2

(令) 与 (定义) 可以混合使用:

meta-lisp
(循序
  (令 ((一 1))
    (定义 a 一)
    (定义 b (整数加 a 一))
    b))  ;; => 2

代数数据类型 ​

代数数据类型(Algebraic data type)是 meta-lisp 的核心数据类型。

meta-lisp 提供了从显式(explicit)到便捷的多种语法来定义数据类型:

语法用途
(定义代数类型)多构造器,所有名字由你指定
(定义结构类型)单构造器,所有名字由你指定
(定义结构)单构造器,按约定生成所有名字
(定义枚举)多构造器,按约定生成所有名字

所有便捷语法最终都展开为 (定义代数类型)。 其中最常用的是 (定义枚举) 和 (定义结构)。

(定义代数类型) ​

meta-lisp
(定义代数类型 <类型名>
  ((<构造器名> (<字段名> <类型>) ...)
   <谓词名>
   (<字段名> <访问器名> <修改器名>)
   ...)
  ...)

(定义代数类型 (<类型名> <类型参数> ...)
  ((<构造器名> (<字段名> <类型>) ...)
   <谓词名>
   (<字段名> <访问器名> <修改器名>)
   ...)
  ...)

代数数据类型(algebraic data type)是构建复合数据结构的核心机制。

(定义代数类型) 是最基础的语法形式,其中所有名字由你显式指定。

只有 <修改器名> 是可选的。 如果不写,这个字段的引用就是不可修改的。

例如:

meta-lisp
(定义代数类型 点型
  ((作点 (横坐标 浮点型) (纵坐标 浮点型))
   为点
   (横坐标 点横坐标 点存横坐标)
   (纵坐标 点纵坐标 点存纵坐标)))

将会生成具有下列类型的函数:

meta-lisp
(声明 作点 (-> 浮点型 浮点型 点型))
(声明 为点 (-> 点型 真假型))
(声明 点横坐标 (-> 点型 浮点型))
(声明 点纵坐标 (-> 点型 浮点型))
(声明 点存横坐标 (-> 点型 浮点型 空值型))
(声明 点存纵坐标 (-> 点型 浮点型 空值型))

使用举例:

meta-lisp
(定义 点 (作点 1.0 2.0))
(为点 点)      ;; => 真
(点横坐标 点)     ;; => 1.0
(点存横坐标 点 3.0)
(点横坐标 点)     ;; => 3.0

对于只有单一构造器的代数类型而言, 谓词 为点 是多余的,没有意义的。 只有代数类型有多个构造器时, 所生成的谓词才有意义。

(定义代数类型) 所定义的类型可以带有类型参数。

例如:

meta-lisp
(定义代数类型 (表型 甲)
  ((空表)
   为空表)
  ((接 (头 甲) (尾 (表型 甲)))
   为接
   (头 接头 接存头)
   (尾 接尾 接存尾)))

将会生成具有下列类型的函数:

meta-lisp
(声明 空表 (泛型 (甲) (-> (表型 甲))))
(声明 为空表 (泛型 (甲) (-> (表型 甲) 真假型)))
(声明 接 (泛型 (甲) (-> 甲 (表型 甲) (表型 甲))))
(声明 为接 (泛型 (甲) (-> (表型 甲) 真假型)))
(声明 接头 (泛型 (甲) (-> (表型 甲) 甲)))
(声明 接尾 (泛型 (甲) (-> (表型 甲) (表型 甲))))
(声明 接存头 (泛型 (甲) (-> 甲 (表型 甲) 空值型)))
(声明 接存尾 (泛型 (甲) (-> (表型 甲) (表型 甲) 空值型)))

(定义结构类型) ​

meta-lisp
(定义结构类型 <类型名>
  (<构造器名> (<字段名> <类型>) ...)
  <谓词名>
  (<字段名> <访问器名> <修改器名>)
  ...)

(定义结构类型 (<类型名> <类型参数> ...)
  (<构造器名> (<字段名> <类型>) ...)
  <谓词名>
  (<字段名> <访问器名> <修改器名>)
  ...)

与 (定义代数类型) 类似,但是只有一个构造器。

meta-lisp
(定义结构类型 点型
  (作点 (横坐标 浮点型) (纵坐标 浮点型))
  为点
  (横坐标 点横坐标 点存横坐标)
  (纵坐标 点纵坐标 点存纵坐标))

等价于:

meta-lisp
(定义代数类型 点型
  ((作点 (横坐标 浮点型) (纵坐标 浮点型))
   为点
   (横坐标 点横坐标 点存横坐标)
   (纵坐标 点纵坐标 点存纵坐标)))

(定义结构类型) 这个语法来自 scheme, 起源于 scheme 48 这个 scheme 方言, 原名 define-record-type(记录类型)。

我们给这个语法加上了 <字段名> 的类型声明, 即 (<字段名> <类型>)。

(定义代数类型) 模仿 (定义结构类型), 进一步支持了多个构造器。

(定义枚举) ​

meta-lisp
(定义枚举 <类型名>
  (<构造器名> (<字段名> <类型>) ...)
  ...)

(定义枚举 (<类型名> <类型参数> ...)
  (<构造器名> (<字段名> <类型>) ...)
  ...)

定义多个构造器的代数数据类型。 每个构造器按照约定生成谓词、访问器和修改器的名字。

meta-lisp
(定义枚举 项型
  (变量项 (名 符号型))
  (作用项 (目标 项型) (参数 项型))
  (函项 (形参 符号型) (体 项型)))

等价于:

meta-lisp
(定义代数类型 项型
  ((变量项 (名 符号型))
   为变量项
   (名 变量项名 变量项存名))
  ((作用项 (目标 项型) (参数 项型))
   为作用项
   (目标 作用项目标 作用项存目标)
   (参数 作用项参数 作用项存参数))
  ((函项 (形参 符号型) (体 项型))
   为函项
   (形参 函项形参 函项存形参)
   (体 函项体 函项存体)))

对于某个给定的 <构造器名> 生成其名字的规则如下:

  • <谓词名> = 为<构造器名> -- 为变量项
  • <访问器名> = <构造器名><字段名> -- 变量项名
  • <修改器名> = <构造器名>存<字段名> -- 变量项存名

(定义结构) ​

meta-lisp
(定义结构 <类型名>
  (<字段名> <类型>)
  ...)

(定义结构 (<类型名> <类型参数> ...)
  (<字段名> <类型>)
  ...)

定义单构造器结构体。 <类型名> 类型名必须以 型 结尾, 格式为 <基名>型。 其中 <基名> 将被用于生成其他名字。

meta-lisp
(定义结构 点型
  (横坐标 浮点型)
  (纵坐标 浮点型))

等价于:

meta-lisp
(定义代数类型 点型
  ((作点 (横坐标 浮点型) (纵坐标 浮点型))
   为点
   (横坐标 点横坐标 点存横坐标)
   (纵坐标 点纵坐标 点存纵坐标)))

对于某个给定的 <类型名> 生成其名字的规则如下:

  • <类型名> = <基名>型 -- 点型
  • <谓词名> = 为<基名> -- 为点
  • <构造器名> = 作<基名> -- 作点
  • <访问器名> = <基名><字段名> -- 点横坐标
  • <修改器名> = <基名>存<字段名> -- 点存横坐标

(匹配) ​

meta-lisp
(匹配 <目标>
  (<模式> <函数体>)
  ...)

用模式匹配的方式解构代数数据类型。

meta-lisp
(定义枚举 项型
  (变量项 (名 符号型))
  (作用项 (目标 项型) (参数 项型))
  (函项 (形参 符号型) (体 项型)))

(定义 (求值 项 环境)
  (匹配 项
    ((变量项 名)
     (环境查找 名 环境))
    ((作用项 目标 参数)
     (作用 (求值 目标 环境) (求值 参数 环境)))
    ((函项 形参 体)
     (闭包值 环境 形参 体))))

不透明类型 ​

(定义黑盒类型) ​

meta-lisp
(定义黑盒类型 <类型名> <表示类型>
  (<接口名> <接口类型>)
  ...)

(定义黑盒类型 (<类型名> <类型参数> ...) <表示类型>
  (<接口名> <接口类型>)
  ...)

定义不透明类型,隐藏内部表示。

例如 builtin 中的 匣子型,内部表示为 (数组型 甲):

meta-lisp
(定义黑盒类型 (匣子型 甲) (数组型 甲)
  (作匣子 (-> (匣子型 甲)))
  (匣子为空 (-> (匣子型 甲) 真假型))
  (匣子存 (-> (匣子型 甲) 甲 空值型))
  (匣子取或有 (-> (匣子型 甲) (或有型 甲))))

在实现接口函数的时候,等价于声明了:

meta-lisp
(声明 作匣子 (泛型 (甲) (-> (数组型 甲))))
(声明 匣子为空 (泛型 (甲) (-> (数组型 甲) 真假型)))
(声明 匣子存 (泛型 (甲) (-> (数组型 甲) 甲 空值型)))
(声明 匣子取或有 (泛型 (甲) (-> (数组型 甲) (或有型 甲))))

因此接口函数内部可以使用列表 API 来实现:

meta-lisp
(定义 (作匣子) (作数组))

(定义 (匣子存 匣子 值)
  (若 (匣子为空 匣子)
    (数组末入 匣子 值)
    (数组存 匣子 0 值)))

在使用接口函数的时候,等价于声明了:

meta-lisp
(声明 作匣子 (泛型 (甲) (-> (匣子型 甲))))
(声明 匣子为空 (泛型 (甲) (-> (匣子型 甲) 真假型)))
(声明 匣子存 (泛型 (甲) (-> (匣子型 甲) 甲 空值型)))
(声明 匣子取或有 (泛型 (甲) (-> (匣子型 甲) (或有型 甲))))

外部代码只能通过接口函数来操作 匣子型:

meta-lisp
(声明 匣子取 (泛型 (甲) (-> (匣子型 甲) 甲)))
(定义 (匣子取 匣子)
  (匹配 (匣子取或有 匣子)
    ((有 值) 值)
    ((无) (报错 "匣子为空"))))

模块 ​

一个文件夹可以被视为一个项目(package), 项目中的所有 .meta 文件,都被视为属于这个项目。

一个项目中可以有多个模块(module)。

模块系统与文件系统解耦,存放模块的路径和文件名并不重要。 同一模块的代码,可以拆分到不同文件中。

(模块) ​

meta-lisp
(模块 <模块名>)

声明当前模块。

每个 .meta 文件必带有一个模块声明,一般放在开头。

在同一个项目中,可以通过 <模块名>/<名字> 引用别的模块中的名字。

同一个模块中的函数,就算写在不同的文件中,也可以相互递归。

偶数.meta:

meta-lisp
(模块 例子)

(定义 (为偶数 数)
  (若 (相等 数 0)
    真
    (为奇数 (整数减 数 1))))

奇数.meta:

meta-lisp
(模块 例子)

(定义 (为奇数 数)
  (若 (相等 数 0)
    假
    (为偶数 (整数减 数 1))))

(导入) ​

meta-lisp
(导入 <模块名> <名字> ...)

从其他模块导入指定名字。

导入后可以直接使用,不需要限定前缀。

meta-lisp
(导入 数学 圆周率 周长)

之后,

meta-lisp
数学/圆周率
数学/周长

可简写为:

meta-lisp
圆周率
周长

(导入为) ​

meta-lisp
(导入为 <模块名> <前缀>)

导入模块并修改前缀。

<模块名>/<名字> 改为 <前缀>/<名字>。

meta-lisp
(导入为 元 m)

之后,

meta-lisp
元/项型

可简写为:

meta-lisp
m/项型

(全导入) ​

meta-lisp
(全导入 <模块名>)

导入模块中所有名字。

使得所有名字都可以不用前缀就能引用。

如果当前模块已经有重复的名字, 就略过这个名字不导入。

因此,不带前缀的引用,还是会引用到当前模块自己的名字。 或者说本地的定义,可以覆盖 (全导入) 所引入的定义。

(私有) ​

meta-lisp
(私有 <名字> ...)

将名字标记为私有。

被标记为私有的名字不能被其他模块引用。

meta-lisp
(模块 序号)

(私有 序号散列)
(定义 序号散列 (作散列))

测试 ​

(定义测试) ​

meta-lisp
(定义测试 <测试名> <函数体>)

定义测试。

<函数体> 中可以包含多个断言。

meta-lisp
(声明 加一 (-> 整数型 整数型))
(定义 (加一 数) (整数加 数 1))

(定义测试 加一测试
  (断言相等 2 (加一 1))
  (断言相等 0 (加一 -1)))

支持以下断言:

  • (断言 算式) -- 断言 算式 为 真。
  • (断言非 算式) -- 断言 算式 为 假。
  • (断言相等 左边 右边) -- 断言 左边 与 右边 相等(使用 相等 比较)。
  • (断言不等 左边 右边) -- 断言 左边 与 右边 不相等。