我不知道我在做什么或术语是什么。我只知道我想使用变量(?)来避免在几个地方重复一个值。但我无法使用该变量(?)的值(?)将其传递给emacs lisp中的可选(关键字?)参数。
使用文字值正在运行:
(setq
org-publish-project-alist
'(
("my-notes"
:base-directory "projects/notes"
:base-extension "org"
:publishing-directory "html"
...
)
))
使用变量无效:
(setq my-base-directory "~/projects/notes")
(setq my-publising-directory "html")
(setq
org-publish-project-alist
'(
("my-notes"
:base-directory my-base-directory
:base-extension "org"
:publishing-directory my-publishing-directory
...
)
))
我收到错误:
byte-code: Wrong type argument: stringp, my-base-directory
这也行不通:
(let (
(my-base-directory "~/projects/notes")
(my-publising-directory "html")
)
(setq
org-publish-project-alist
'(
("my-notes"
:base-directory my-base-directory
:base-extension "org"
:publishing-directory my-publishing-directory
...
)
)))
我想知道为什么在emacs中访问变量这么困难?这些变量是定义的(我可以打印它们),但是无法访问它们的可选参数(前面带冒号的那些东西叫做可选参数或关键字参数吗?)
我尝试了无数其他变体,包括(quote ...)
并使用引号'
:
(setq
org-publish-project-alist
'(
("my-notes"
:base-directory 'my-base-directory
:base-extension "org"
:publishing-directory 'my-publishing-directory
...
)
))
在这种情况下我得到:
byte-code: Wrong type argument: stringp, (quote my-base-directory)
我只需要使用变量来设置可选参数。我怎样才能做到这一点?对于可选参数,我是否需要使用与正常使用不同的语法?
答案 0 :(得分:4)
我看到你已经得到了一个有效的答案,但在你的评论中表达了一些困惑;我会尝试更彻底地解释它。
当你引用某些东西时(使用(quote foo)
或'foo
),你告诉lisp解释器不要评估foo。这通常用于输入数据而不是代码;在这种情况下,您将创建一个适度复杂的列表结构以用作数据,而不是作为要评估的代码。
您的代码有'(("my-notes" :base-directory my-base-directory))
,这是列表的引用列表。内部列表将包含关键字:base-directory
和符号my-base-directory
。它不包含my-base-directory变量的值,因为开头的引用告诉lisp不要评估任何一个。
解决这个问题的两种方法都不涉及引用整个表达方式。
第一个也是最简单的选择是使用list
;这是一个函数,它接受任意数量的参数并返回包含这些值的列表。例如:
(list 1 2 3) => '(1 2 3)
(let ((x 42)) (list x x)) => '(42 42)
因此,您可以像这样构建代码:
(setq org-publish-project-alist
(list (list "my-notes" :base-directory my-base-directory
:base-extension "org"
:publishing-directory my-publishing-directory)))
您将看到必须两次调用list
函数,每个级别的结构一次。随着结构变得更加复杂,这可能会变得乏味;引用是为了拯救你这个乏味而发明的。
(另请注意,关键字和字符串会自行评估,因此当用作参数而不是引用列表的成员时,它们不需要任何特殊处理。)
另一种选择是使用反引号(或偶尔称为语法引用)而不是正常quote
。反引用是不寻常的,因为它可以使用逗号运算符撤消:
(setq org-publish-project-alist
`(("my-notes" :base-directory ,my-base-directory
:base-extension "org"
:publishing-directory ,my-publishing-directory)))
反引用告诉lisp不要像正常引用那样评估表达式,但是稍后在逗号上让你改变主意并让lisp评估一些表达式。
Backquotes有点像Python的字符串插值,除了它们适用于整个lisp语法而不仅仅是双引号字符串。
此外,您可以在逗号后添加任意lisp表达式,就像您可以在引号或反引号后面放置任意lisp表达式一样:
`(("my-notes" :base-directory ,(concat my-projects-directory "notes")))
特别注意`((“my-notes”:base-directory,my-base-directory))不起作用;你的一条评论表明你可能尝试过这样的事情。这种逗号的使用对来自其他语言的程序员来说确实很陌生!你不是一个人认为这是一种非常奇怪的写东西的方式,但过了一段时间它确实开始有意义。将逗号视为一种颠倒的反引号是有帮助的。
答案 1 :(得分:3)
示例:
反引号列表:
ELISP> (let ((foo "Foo")) `(,foo bar))
("Foo" bar)
功能LIST
:
ELISP> (let ((foo "Foo")) (list foo 'bar))
("Foo" bar)
示例:
(setq
org-publish-project-alist
`(("my-notes"
:base-directory ,my-base-directory
:base-extension "org"
:publishing-directory ,my-publishing-directory
; ...
)))