Racket 骗局:你如何使用一个参数的值作为一个符号?

Racket 骗局:你如何使用一个参数的值作为一个符号?,racket,Racket,我是个新手,正在努力寻找合适的词语来解释我要做的事情。我能想到的最好办法是:如何使用参数的值作为符号,而不调用与参数值同名的函数,也不只是引用参数的名称 这里有一个简单的例子来说明这一点 有一个名为ul的函数,它执行一些操作 还有另一个名为生成列表的函数,它有一个参数,列表类型 还有第三个函数,makeul,它使用参数ul调用makelist 在true分支中,应用函数ul。到目前为止还不错 在false分支中,我希望能够使用参数值作为符号,在本例中,参数值是'ul。实际上,这行代码将运行(λa

我是个新手,正在努力寻找合适的词语来解释我要做的事情。我能想到的最好办法是:如何使用参数的作为符号,而不调用与参数值同名的函数,也不只是引用参数的名称

这里有一个简单的例子来说明这一点

有一个名为
ul
的函数,它执行一些操作

还有另一个名为
生成列表
的函数,它有一个参数,
列表类型

还有第三个函数,
makeul
,它使用参数
ul
调用
makelist

在true分支中,应用函数
ul
。到目前为止还不错

在false分支中,我希望能够使用参数值作为符号,在本例中,参数值是
'ul
。实际上,这行代码将运行
(λargs(list*'ul args))
。我如何做到这一点

#朗球拍
(定义(ul.xs)`(div,@xs))
(定义(制作列表类型)
(如果(相等?“某物”或其他)
(λargs(应用列表类型args));真分支:调用函数“ul”
(λargs(列表*列表类型args));false branch:如何在不调用“ul”函数的情况下使用`ul?
(定义制造ul(制造列表ul))

如果你的目标是写出好的拍子代码,那么最好的答案就是不要。 添加单独的参数以获取符号,如下所示:

;; make-list : Procedure Symbol -> Any ... -> Any
(define (make-list proc tag-sym)
  (if ....
      proc ;; (λ args (apply proc args)) simplifies to just proc
      (λ args (list* tag-sym args))))

(define make-ul (make-list ul 'ul))
或者,如果分支独立于
args
,则可以只使用一个
(U过程符号)
类型的参数:

;; make-list : (U Procedure Symbol) -> Any ... -> Any
(define (make-list list-type)
  (cond [(procedure? list-type)
         ;; (λ args (apply list-type args))
         list-type]
        [(symbol? list-type)
         (λ args (list* list-type args))]))

(define make-ul (make-list ul))
(define make-li (make-list 'li))

如果你想探索球拍的特点,有两种主要的方法

  • 可以创建一个宏,该宏采用过程名称,并将其用作引用和引号作为符号。例如,使用上面的
    制作列表的第一个版本:

    (define-syntax-rule (make-list* proc-name) (make-list proc-name (quote proc-name)))
    
    (define make-ul (make-list* ul)) ;; => (define make-ul (make-list ul 'ul))
    
  • 您可以在过程中调用
    对象名称
    ,询问Racket认为它的名称是什么。例如,
    (对象名称列表)
    返回
    'list
    ,而
    (对象名称ul)
    应返回
    'ul
    。但是
    (对象名make-ul)
    不会返回
    'make-ul
    ,因为Racket在编译时跟踪名称,而不是在运行时。(我建议不要编写依赖于
    对象名称的代码;这会使代码非常脆弱。)


  • 我真的很感谢你的回答。你不仅解决了这个问题,还帮助我从不同的角度思考这个问题。我现在已经阅读了有关宏的内容,可以看到它们将如何解决这个问题,但如何添加一个额外的参数将是最简单的解决方案。再次感谢你!