定义 Racket 的一个子集
Define a subset of Racket
由于 Racket 以其创建新编程语言的能力而闻名,因此以下内容应该不会太难。
我想创建一个 Racket 的子集(我们将其命名为 min
)用于教育目的,重命名某些功能(tail
而不是 cdr
)并忽略其他功能(例如因为 string=?
和 =
只有 equal?
).
我做的第一步是用 #lang s-exp "min.rkt"
启动我的 min
文件,但我卡在了扩展器阶段。
以下模块是 Racket 的最小子集的示例,它允许使用 +
和 *
的 top-level 定义、常量和算术:
;; min.rkt
#lang racket/base
(provide #%module-begin #%top-interaction
#%app #%datum #%top
define + *)
提供的含义如下:
#%module-begin
必须 由一个模块提供,该模块被认为是一种“语言”;它决定了模块主体的含义。你可以重用 Racket 的 module-begin 宏。 (#%module-begin
导出为您提供了一个钩子来实现 non-local 约束或转换。例如,如果您想添加类型检查器或检查变量是否定义在按字母顺序排列,您可以在 module-begin 挂钩中执行此操作。)
#%top-level
是交互式语言所必需的。如果你遗漏了它,你就不能为你的语言使用 REPL(例如,racket -t "min.rkt" -i
)。
#%app
和 #%datum
使函数应用程序和 self-evaluating 常量(如数字和布尔值)起作用。
#%top
使前向引用在 REPL 中起作用,就像在 mutually-recursive 函数中一样。当然,在评估对它的引用之前,您仍然必须定义一个名称。
- 其余的导出是您希望包含在您的语言中的特殊形式和函数。
这是使用这种 "min.rkt"
语言的程序:
#lang s-exp "min.rkt"
(define x 2)
(define y (+ x 5))
(* y 7)
(define (f x) (+ x x 1))
(f 8)
请注意,由于该语言包含 Racket 的 define
,它允许函数定义,即使该语言不包含 lambda
。如果您想要 define
的受限版本,则必须定义自己的宏并将其提供为您的语言的 define
,例如 (provide (rename-out [my-define define]))
.
您还可以使用 rename-out
将 Racket 的 cdr
提供为 tail
,但该过程仍将打印为 #<procedure:cdr>
,如果它引发错误,则错误消息仍然会说 cdr
。要更改它,您需要定义自己的包装函数来进行自己的错误检查。
由于 Racket 以其创建新编程语言的能力而闻名,因此以下内容应该不会太难。
我想创建一个 Racket 的子集(我们将其命名为 min
)用于教育目的,重命名某些功能(tail
而不是 cdr
)并忽略其他功能(例如因为 string=?
和 =
只有 equal?
).
我做的第一步是用 #lang s-exp "min.rkt"
启动我的 min
文件,但我卡在了扩展器阶段。
以下模块是 Racket 的最小子集的示例,它允许使用 +
和 *
的 top-level 定义、常量和算术:
;; min.rkt
#lang racket/base
(provide #%module-begin #%top-interaction
#%app #%datum #%top
define + *)
提供的含义如下:
#%module-begin
必须 由一个模块提供,该模块被认为是一种“语言”;它决定了模块主体的含义。你可以重用 Racket 的 module-begin 宏。 (#%module-begin
导出为您提供了一个钩子来实现 non-local 约束或转换。例如,如果您想添加类型检查器或检查变量是否定义在按字母顺序排列,您可以在 module-begin 挂钩中执行此操作。)#%top-level
是交互式语言所必需的。如果你遗漏了它,你就不能为你的语言使用 REPL(例如,racket -t "min.rkt" -i
)。#%app
和#%datum
使函数应用程序和 self-evaluating 常量(如数字和布尔值)起作用。#%top
使前向引用在 REPL 中起作用,就像在 mutually-recursive 函数中一样。当然,在评估对它的引用之前,您仍然必须定义一个名称。- 其余的导出是您希望包含在您的语言中的特殊形式和函数。
这是使用这种 "min.rkt"
语言的程序:
#lang s-exp "min.rkt"
(define x 2)
(define y (+ x 5))
(* y 7)
(define (f x) (+ x x 1))
(f 8)
请注意,由于该语言包含 Racket 的 define
,它允许函数定义,即使该语言不包含 lambda
。如果您想要 define
的受限版本,则必须定义自己的宏并将其提供为您的语言的 define
,例如 (provide (rename-out [my-define define]))
.
您还可以使用 rename-out
将 Racket 的 cdr
提供为 tail
,但该过程仍将打印为 #<procedure:cdr>
,如果它引发错误,则错误消息仍然会说 cdr
。要更改它,您需要定义自己的包装函数来进行自己的错误检查。