首页 > 解决方案 > 定义 Racket 的子集

问题描述

由于 Racket 以其创建新编程语言的能力而闻名,因此以下内容应该不会太难。

我想创建一个 Racket 的子集(让我们命名它min),用于重命名某些功能(tail而不是cdr)并忽略其他功能(例如string=?and =to just have equal?)。

我做的第一步是开始我的min文件,#lang s-exp "min.rkt"但我被困在扩展器阶段。

标签: lispracket

解决方案


+以下模块是 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(例如,with racket -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 的cdras tail,但该过程仍会打印 as #<procedure:cdr>,如果它引发错误,错误消息仍会显示cdr。要改变这一点,您需要定义自己的包装函数来进行自己的错误检查。


推荐阅读