如何在 Racket 中提供函数列表?

How do I provide a list of functions in Racket?

如果我想在当前模块之外使用某个功能,我可以执行以下操作...

(provide my-function)

我可以为函数列表执行此操作吗?

我尝试了以下...

(define f1 ...) ; body omitted for clarity
(define f2 ...) ; ditto

(define my-funs '(f1 f2))

(provide my-funs)

...但是当我尝试时,它给出了“Unbound identifier in: f1”。

我可以这样做吗?谢谢

更新: 只是为了澄清我在这里想做什么,我正在学习 Beautiful Racket,并且正在做第一个教程。在他 defines the expander 的阶段,他添加了一个 handle 函数来处理运算符...

(define (handle [arg #f])
  (cond
    [(number? arg) (push-stack! arg)]
    [(or (equal? * arg) (equal? + arg))
     (define op-result (arg (pop-stack!) (pop-stack!)))
     (push-stack! op-result)]))

但是,为了完成这项工作,他 provide 同时 +*...

(provide + *)

这意味着这两个运算符被硬编码了两次。添加对其他运算符的支持时,您需要修改 handle 函数和 provide 调用。我正在尝试确定我们是否可以定义一个运算符列表,并在两者中使用它,因此您只需进行一次修改即可支持新的运算符。

不,你不能这样做。

您可以使用 filtered-out and begin-for-syntax 导出函数列表(如下所示),但这会阻止您在代码中使用该列表。

正在导出列表

#lang racket

(module fns racket
  (require racket/provide)
  (define (f1 a) (+ a 1))
  (define (f2 a) (+ a 2))

  (begin-for-syntax
    (define my-funs '(f1 f2)))

  (provide
    (filtered-out
      (λ (name) (and (member (string->symbol name) my-funs) name))
      (all-defined-out))))

(require 'fns)
(display (f1 2))

这是如何运作的

provide 可以采用任意数量的 provide-spec 形式,指定多个 provide-spec 等同于编写多个 provide 形式。可用的 provide-spec 形式之一是 all-defined-out,它将导出模块中所有已定义的符号(如果未明确指定模块,则导出文件)。

通过要求 racket/provide,我们可以访问可以转换和操作 provide-spec 表单的辅助函数; filtered-out 尤其允许我们 运行 任意代码覆盖 provide-spec 和 return 一个有效的 provide-spec。 (所需的 proc-expr 是一个函数,它接受一个字符串(导出标识符的字符串值)和 returns 一个字符串或一个假值。这就是为什么在使用 member 时,我们将它包装起来在 and 和 return 原始名称本身。这也可以通过 findf 完成: (λ (name) (findf (λ (n) (equal? (string->symbol name) n)) my-funs)))

然而,这还不够,因为 provide 是在“编译时”执行的,这意味着我们的列表 my-funs 尚不可用。为了处理这个问题,我们需要将该定义包装在 begin-for-syntax 中,这使得绑定在“编译时”也可用。但是,通过将 my-funs 移动到“编译时”,您将失去在非“编译时”代码中使用 my-funs 的能力。这意味着,例如,您不能说 (cond ... [(member arg my-funs) ...]):

(define (handle [arg #f])
  (cond
    [(number? arg) (push-stack! arg)]
    [(member arg my-funs)
              ;; ^--- Error here with "my-funs: unbound identifier"
     (define op-result (arg (pop-stack!) (pop-stack!)))
     (push-stack! op-result)]))