Я не знаю, что делаю и какова терминология. Я знаю только, что хочу использовать переменную (?), Чтобы не повторять значение в нескольких местах. Но я не могу использовать значение (?) Этой переменной (?), Чтобы передать его в необязательный (ключевое слово?) Аргумент в 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
blueFast 26 Окт 2015 в 21:35

2 ответа

Лучший ответ

Примеры:

Список в обратной кавычке:

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
  ;  ...
    )))
3
Rainer Joswig 26 Окт 2015 в 19:36

Я вижу, у вас уже есть рабочий ответ, но вы выразили некоторую путаницу в своих комментариях; Тогда я постараюсь объяснить это более подробно.

Когда вы что-то цитируете (используя (quote foo) или 'foo), вы говорите интерпретатору лиспа не оценивать 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 оценивает некоторые выражения.

Обратные кавычки немного похожи на интерполяцию строк в Python, за исключением того, что они применяются ко всему синтаксису lisp, а не только к строкам, заключенным в двойные кавычки.

Кроме того, вы можете помещать произвольные выражения Lisp после запятой, так же как вы можете помещать произвольные выражения Lisp после цитаты или обратной кавычки:

`(("my-notes" :base-directory ,(concat my-projects-directory "notes")))

Обратите особое внимание на то, что `((" my-notes ": base-directory, my-base-directory)) не будет работать; один из ваших комментариев указывает на то, что вы, вероятно, пробовали что-то подобное. Такое использование запятой действительно совершенно чуждо программистам, пришедшим с других языков! Не только вы думаете, что это очень странный способ писать вещи, но через некоторое время он начинает обретать смысл. Это помогает думать о запятой как о перевернутой обратной кавычке.

4
db48x 27 Окт 2015 в 19:07