【问题标题】:What is the Scheme equivalent of this alias code written in CL?用 CL 编写的这个别名代码的 Scheme 等效项是什么?
【发布时间】:2018-09-13 15:38:32
【问题描述】:

我正在尝试编写与此 CL 代码等效的 Scheme:

(defmacro alias (new-name prev-name)
  `(defmacro ,new-name (&rest args)
     `(,',prev-name ,@args)))

;; Sample use:
(alias co concatenate)

我的目标是能够使用符号和函数名称的简写名称,例如:

(alias sa string-append)
(sa "ok" "not ok") 

为此,我已经尝试过,但没有成功:

(define-syntax alias (new-name prev-name)
   `(define-syntax ,new-name (#!rest args)
     `(,',prev-name ,@args)))

感谢任何帮助。谢谢。

【问题讨论】:

  • 嗯,Common Lisp 等价物是使用符号宏(参见define-symbol-macro 和symbol-macrolet)。
  • 您将如何使用这些宏之一编写别名功能?
  • 抱歉,没看错。

标签: scheme common-lisp


【解决方案1】:

您可以使用定义另一个 syntax-rules 宏的 syntax-rules 宏轻松做到这一点:

(define-syntax alias
  (syntax-rules ()
    ((_ new-name prev-name)
     (define-syntax new-name
       (... (syntax-rules ()
              ((_ arg ...)
               (prev-name arg ...))))))))

最棘手的是这个宏是使用... 来逃避... 的嵌套使用。

但是,这不一定是最好的方法。最好的方法可能取决于您精确的 Scheme 实现,因为 Scheme 与其说是一种语言,不如说是一种语言家族。编写可移植的 Scheme 通常不是很有用。

【讨论】:

  • 感谢您的回答。当我在我的鸡计划上尝试它时,它给出了这个错误:错误:在扩展(语法规则......)期间 - 太多省略号:(arg ...)你能帮忙吗?顺便说一句,虽然 CL 上有几十本优质书籍和网站,但只有几本 Scheme 书籍,所有这些书籍都没有多大用处,而且网站和教程也很少,这限制了我的学习体验。
  • @Romario 听起来 Chicken 在这方面不符合 R7RS,那么 R7RS 要求允许 ... 作为转义。我认为这是 Chicken 中的一个错误,但您的问题实际上并未指定您想要答案的方案版本(R5RS/R6RS/R7RS)或实现。不过,要回答你的另一个问题,我会放弃尝试编写可移植的 Scheme,而只写 Racket,这是一个有能力、有据可查的 Scheme 后代。当然,您也可以使用 Scheme 实现,但我会将它们视为独立的语言。
  • @Romario 看起来鸡计划默认情况下不启用 R7RS 合规性,但如果你打开它,这个答案会起作用。差异记录在here。
  • 在我应用了 R7RS 扩展库(“egg”)之后,效果非常好!现在别名功能完美无缺。更重要的是,它是一段很好的代码来学习 Scheme 的一些血腥细节。顺便说一句,我的鸡计划版本是最新的 4.13.0。我只是不会猜测版本对那个特定问题很重要:)
  • 如果你想要一个方案教程,虽然是针对 R6RS,scheme.com/tspl4 是一个很棒的学习资源。 gnu.org/software/guile/manual/html_node/Hello-Scheme_0021.html 和 guile 手册的其余部分也是一个很好的资源。
【解决方案2】:

如果您的方案支持 R6RS 语法大小写和同源(例如,guile 或 chez 方案),则标识符语法是实现您想要的最直接的方法:

(define-syntax new-name (identifier-syntax old-name))

因此:

(define-syntax new-display (identifier-syntax display))
(new-display "hello\n")

编辑:我看到你用的是鸡肉。在这种情况下,您可以使用 er-macro-transformer 重现您的 defmacro 解决方案(无论如何,这适用于 chicken-4.10.0):

(define-syntax alias
  (er-macro-transformer
   (lambda (exp r c)
     (let ([new-name (cadr exp)]
           [old-name (caddr exp)])
       `(define-syntax ,new-name
          (ir-macro-transformer
           (lambda (exp i c)
             `(,',old-name ,@(cdr exp)))))))))

【讨论】:

  • 这个版本的别名看起来更类似于 CL 代码。 er-macro-transformer 使这成为可能。我已经在我的 Chicken Scheme-4.13.0 上尝试过这个并且它有效。所以这是一个很好的解决方案。谢谢!
  • 不要忘记,因为方案中只有一个命名空间,所以您可以而且经常会以牺牲另一个符号为代价来执行 '(define new-name old-name)'。跨度>
【解决方案3】:

顺便说一句,在 Common Lisp 中,您可以通过设置 symbol-function 的符号来表示这样的别名,从而使别名成为真正的函数,而不是宏:

CL-USER> (defun foo (name)
           (format nil "Hello ~A!~%" name))
FOO
CL-USER> (setf (symbol-function 'bar)
               #'foo)
#<INTERPRETED-FUNCTION FOO>
CL-USER> (bar "Bob")
"Hello Bob!
"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-28
    • 2014-02-20
    • 2015-07-19
    • 2019-09-01
    • 2016-01-06
    • 1970-01-01
    相关资源
    最近更新 更多