lisp - 定义 Racket 的子集
问题描述
由于 Racket 以其创建新编程语言的能力而闻名,因此以下内容应该不会太难。
我想创建一个 Racket 的子集(让我们命名它min
),用于重命名某些功能(tail
而不是cdr
)并忽略其他功能(例如string=?
and =
to just have equal?
)。
我做的第一步是开始我的min
文件,#lang s-exp "min.rkt"
但我被困在扩展器阶段。
解决方案
+
以下模块是 Racket 的最小子集的示例,它允许使用and进行顶级定义、常量和算术运算*
:
;; min.rkt
#lang racket/base
(provide #%module-begin #%top-interaction
#%app #%datum #%top
define + *)
以下是提供的含义:
#%module-begin
必须由模块提供,该模块才能被视为“语言”;它决定了模块主体的含义。你可以重用 Racket 的 module-begin 宏。(#%module-begin
导出为您提供了一个实现非局部约束或转换的钩子。例如,如果您想添加一个类型检查器或检查变量是否按字母顺序定义,您可以在 module-begin 钩子中执行此操作。)#%top-level
是交互式语言所必需的。如果您忽略它,您就不能为您的语言使用 REPL(例如,withracket -t "min.rkt" -i
)。#%app
并使#%datum
函数应用和自评估常量(如数字和布尔值)起作用。#%top
使前向引用在 REPL 中工作,就像在相互递归函数中一样。当然,在评估对它的引用之前,您仍然必须定义一个名称。- 其余的导出是您想要包含在您的语言中的特殊形式和功能。
这是该"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
as tail
,但该过程仍会打印 as #<procedure:cdr>
,如果它引发错误,错误消息仍会显示cdr
。要改变这一点,您需要定义自己的包装函数来进行自己的错误检查。
推荐阅读
- javascript - JQuery AJAX,成功时从表中删除,不成功时保留
- c# - 有没有办法覆盖类中的 app.config 设置(C#)
- python - 带有 altair 的简单折线图
- java - 更新到最新依赖后的 Firestore 错误
- javascript - 减少 redux-thunk 样板代码
- javascript - 带有 JSON 数据源的自动完成文本框
- c++ - 有没有办法删除传递给函数 `foo (new Object())` 的对象?
- php - 让批量更新在 laravel 5.6 中工作
- xaml - 如何在列表视图 xamarin Forms 中仅添加一次按钮
- php - 根据另一个数组的键减少数组/子数组/对象