如何在ELisp中创建命名参数?

 eea1051113 发布于 2022-12-19 11:44

我认为既然Emacs Lisp和Common Lisp在语法方面看起来非常相似,我可以按照我在RosettaCode上找到的示例代码,但事实证明我错了.

有问题的代码如下所示:

(defun print-name (&key first (last "?"))
  (princ last)
  (when first
    (princ ", ")
    (princ first))
  (values))

根据RosettaCode,它应该执行以下操作:

> (print-name)
  ?
> (print-name :first "John")
  ?, John
> (print-name :last "Doe")
  Doe
> (print-name :first "John" :last "Doe")
  Doe, John

现在,这就是事情; 每当我尝试在我的ELisp解释器中运行该函数时,我都会收到以下错误:

*** Eval error ***  Wrong number of arguments: (lambda (&key first (last "?")) (princ la\
st) (if first (progn (princ ", ") (princ first))) (values)), 0

我在lisp中没有足够的常规来知道这应该是什么意思,并且没有任何谷歌搜索让我更接近答案.

那么在Emacs Lisp中这样做的正确方法是什么?

2 个回答
  • 由于Emacs Lisp不直接支持关键字参数,因此您需要模拟这些参数,或者使用cl-defun其他答案,或者将参数解析为plist:

    (defun print-name (&rest args)
      (let ((first (plist-get args :first))
            (last (or (plist-get args :last) "?")))
        (princ last)
        (when first
          (princ ", ")
          (princ first))))
    

    &rest args告诉Emacs将所有函数参数放入一个列表中. plist-get从属性列表中提取值,即格式列表(key1 value1 key2 value2 …).实际上,plist是扁平的alist.

    这可以让你print-name像在你的问题中一样打电话:

    > (print-name)
      ?
    > (print-name :first "John")
      ?, John
    > (print-name :last "Doe")
      Doe
    > (print-name :first "John" :last "Doe")
      Doe, John
    

    2022-12-19 11:46 回答
  • elisp的的defun不支持&key(它不支持&optional&rest,虽然).有一个宏可以让你使用定义函数&key.在Emacs 24.3及更高版本中,您可以要求cl-lib并使用cl-defun:

    (require 'cl-lib)
    (cl-defun print-name (&key first (last "?"))
       ...
    

    在早期的Emacs版本中,相同的功能在cl库中的名称下defun*:

    (require 'cl)
    (defun* print-name (&key first (last "?"))
       ...
    

    cl-lib库是首选cl,因为它通过在所有符号前加上来保持名称空间整洁cl-; 但是,如果您需要与早期的Emacs版本兼容,您可能更喜欢cldefun*.


    示例中的函数还包含对函数的调用values.此函数特定于Common Lisp,但可以在cl-valuesin cl-libvaluesin中使用cl.

    但是,替代方案与Common Lisp对应方法的工作方式完全不同.Common Lisp具有多个返回值的概念.例如,调用(values 1 2 3)将返回三个值 - 并且(values)如上所述调用将返回零值.Emacs Lisp函数通过列表模拟多个返回值,并重新定义multiple-value-bind匹配.这意味着调用(cl-values)将返回nil(空列表).

    在这样的Emacs Lisp函数中,您要么显式指定返回值nil,要么完全不将它保留,将最后一个表单的返回值保留为函数的返回值,因为调用者不应该使用回报价值.

    2022-12-19 11:47 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有