Я упускаю какой-то важный факт об интернировании символов в LISP?

#lisp #symbols

#lisp #символы

Вопрос:

Если быть кратким. Вот мои несколько попыток интернировать и использовать символ в clisp.

  [1]> (setq sym (intern "foo"))
 |foo|
 [2]> (eq sym 'foo)
 NIL
  

Почему???

  [3]> (defun internup (me amp;optional (package *package*))
   (intern (string-upcase me) package))
 INTERNUP

 [4]> (eq 'abc (internup "abc"))
 T
  

Вероятно, должно быть upcase.

  [12]>(let ((abc 2))
   (eval '(  2 abc)))

 *** - EVAL: variable ABC has no value
 The following restarts are available:
  

ОК

  [18]> (let ((abc 2))
 (eval '(  2 'abc)))

 *** -  : ABC is not a number
 The following restarts are available:
  

Интересно. Должен ли я установить это раньше.

  [14]> (setq a (internup "abc"))
 ABC

 [15]> (let ((abc 2))
 (eval '(  2 a)))

 *** -  : ABC is not a number
 The following restarts are available:
  

И снова неправильно. Хм, я, должно быть, упускаю какой-то важный факт об интернировании символов в LISP. Вы можете мне помочь?

Комментарии:

1. (setf (symbol-value a) 2) будет установлено 'ABC значение 2 .

Ответ №1:

Ваша проблема не имеет ничего общего с интернированием.

Первая проблема действительно вызвана тем фактом, что считыватель всегда будет использовать символы верхнего регистра, поэтому вам нужно вызвать (intern «FOO»), чтобы получить тот же результат, что и ‘foo.

Проблема с EVAL вызвана тем фактом, что LET вводит лексическую привязку, которая не видна внутри EVAL. Если вы действительно хотите, чтобы это сработало, вам нужно было бы объявить abc специальным, вот так:

 (let ((abc 2))
    (declare (special abc))
    (eval '(1  abc)))
  

Специальное объявление приведет к тому, что переменная будет иметь динамическую привязку вместо лексической привязки (последнее означает, что привязка ограничена локальным лексическим контекстом, то есть в форме LET. С помощью специального объявления переменная доступна для всего, что вызывается из этой формы).

Обратите внимание, что вам следует быть очень осторожным с использованием как специальных объявлений, так и eval, и вам, вероятно, в первую очередь следует пересмотреть свое использование EVAL. Очень редко вам действительно нужно это использовать. В большинстве случаев вы на самом деле ищете использование лямбда-функций вместо этого.

Комментарии:

1. Большое вам спасибо. Но что именно вы имеете в виду под использованием лямбда-функции. Я работаю над mathematical symbolic evaluator и не могу представить иной подход, чем вызов функции eval. (eval (diff (make-equation database) ‘x))

2. EVAL вычислит выражение в нулевой лексической среде. LET (обычно) устанавливает лексические привязки. Итак, чтобы получить доступ к переменной из EVAL, это должна быть динамическая привязка, поэтому потребуется либо специальное объявление для привязки, либо объявление, установленное DEFVAR или DEFPARAMETER .

Ответ №2:

Eval оценивает форму в нулевой лексической среде, то есть без лексических привязок. Это не имеет никакого отношения к интернированию символов.

Ответ №3:

Чувствительность Common Lisp Reader к регистру определяется таблицей чтения:

 (readtable-case *readtable*)
  

Обычно читатель изначально вводит символы в верхнем регистре (если вы явно не экранируете символы). Следовательно:

(eq (intern "foo") 'foo) => НОЛЬ

(eq (intern "FOO") 'foo) => T

(eq (intern "FOo") 'foo) => T

Вы можете использовать синтаксис обратных кавычек для построения формы для eval:

 (let ((abc 2))
  (eval `(  2 ,abc)))
  

=> 4

Комментарии:

1.Просто для пояснения: эта форма обратной кавычки эквивалентна (list (quote ) (quote 2) abc) , которая соответствует списку ( 2 2) , который затем передается eval . Явный eval вызов никогда не видит переменную abc .