Разница между let * и set? в Common Lisp

Я работаю над хобби-проектом по генетическому программированию.

У меня есть настройка функции / макроса, которая при оценке в форме setq / setf сгенерирует список, который будет выглядеть примерно так.

(setq trees (make-trees 2)) 
==> (+ x (abs x))

Затем он будет привязан к лямбда-функции #<FUNCTION :LAMBDA (X) ... > посредством стратегического использования функций / макросов.

Однако я хочу, чтобы это было немного эффективнее, чем ручное присвоение переменных, поэтому я написал что-то вроде этого:

(setq sample 
      (let* ((trees (make-trees 2))
         (tree-bindings (bind-trees trees))
         (evaluated-trees (eval-fitness tree-bindings))))
      (list (trees tree-bindings evaluated-trees)))

Однако я получаю EVAL: trees has no value, когда помещаю это в форму let. Я подозреваю, что расширения макросов не выполняются полностью в LET по сравнению с SETF, но для меня это не имеет смысла.

В чем причина этой проблемы?

--- редактировать: выдернул мой код и поместил весь файл в pastebin ---

Предположим, я решил, что setq не сделает этого за меня, и я написал простую функцию для этого:

(defun generate-sample () (let ((twiggs (make-tree 2))) (let ((tree-bindings (bind-tree-twiggs))) (let ((оцененные-деревья (eval-fit-tree-bindings) ))
(список деревьев-привязок twiggs, оцененных-деревьев)))))

Это приводит к огромному количеству ... сообщений об ошибках файла справки (??!?) ... и "eval: переменная twiggs не имеет значения", что происходит из определения деревьев связывания при проверке SLIME.

Я достаточно уверен, что полностью залил свои макросы. http://pastebin.org/673619


person Paul Nathan    schedule 19.08.2010    source источник
comment
Я не совсем понимаю, что делает ваш макрос. И каково ваше стратегическое использование функций / макросов и что со всеми setq верхнего уровня?   -  person Ken    schedule 19.08.2010
comment
Ну, один набор - это своего рода глобальный «пул населения»; остальные - просто артефакты развития. Мои макросы динамически генерируют функцию из довольно произвольных деревьев выражений (об этом довольно сложно думать).   -  person Paul Nathan    schedule 19.08.2010
comment
Ваш второй фрагмент неполный. Что происходит в теле вашей let формы? Отступ также вводит в заблуждение, и круглые скобки не сбалансированы.   -  person Svante    schedule 19.08.2010


Ответы (1)


(Setq make-trees 2) устанавливает значение переменной make-trees на 2, затем возвращает 2.

Не вижу смысла использовать макрос в том, что вы описываете. Верно ли, что ваш make-trees создает одно случайное дерево, которое можно интерпретировать как программу? Просто определите это как функцию с defun. Я думаю примерно так:

(defun make-tree (node-number)
  (if (= node-number 1)
      (make-leaf)
      (cons (get-random-operator)
            (mapcar #'make-tree
                    (random-partition (- node-number 1)))))) 

Let и setq делают совершенно разные вещи. Setq присваивает значение существующей переменной, а let создает новую лексическую область видимости с рядом лексических привязок.

Я думаю, вам следует представить больше своего кода; в настоящее время ваш вопрос не имеет большого смысла.


Обновление:

Я исправлю отступ в вашем фрагменте, чтобы было понятнее:

(setq sample 
      (let* ((trees (make-trees 2))
             (tree-bindings (bind-trees trees))
             (evaluated-trees (eval-fitness tree-bindings))))
      (list (trees tree-bindings evaluated-trees)))

Теперь, как было написано ранее, let* устанавливает лексические привязки. Это только в пределах его тела:

(setq sample 
      (let* ((trees (make-trees 2))
             (tree-bindings (bind-trees trees))
             (evaluated-trees (eval-fitness tree-bindings)))
        ;; here trees, tree-bindings, and evaluated-trees are bound
        ) ; end of let* body
      ;; here trees, tree-bindings, and evaluated trees are not in scope anymore
      (list (trees tree-bindings evaluated-trees)))

Эта последняя строка тоже ложная. Если бы эти имена были связаны, он вернул бы список из одного элемента, который был бы результатом оценки функции trees с tree-bindings и evaluated-trees в качестве аргументов.

Вы можете получить то, что хотите, вот так:

(setq sample 
      (let* ((trees (make-trees 2))
             (tree-bindings (bind-trees trees))
             (evaluated-trees (eval-fitness tree-bindings)))
        (list trees tree-bindings evaluated-trees)))

Еще одно обновление:

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

Вот код, который может вам помочь:

(defun make-tree-lambda (depth)
  (list 'lambda '(x)
        (new-tree depth)))

(defun make-tree-function (lambda-tree)
  (eval lambda-tree))

(defun eval-fitness (lambda-form-list input-output-list)
  "Determines how well the lambda forms approach the wanted function
by comparing their output with the wanted output in the supplied test
cases.  Returns a list of mean quadratic error sums."
  (mapcar (lambda (lambda-form)
            (let* ((actual-results (mapcar (make-tree-function lambda-form)
                                           (mapcar #'first input-output-list)))
                   (differences (mapcar #'-
                                        actual-results
                                        (mapcar #'second input-output-list)))
                   (squared-differences (mapcar #'square
                                                differences)))
              (/ (reduce #'+ squared-differences)
                 (length squared-differences))))
          lambda-form-list))

(defun tree-fitness (tree-list input-output-list)
  "Creates a list of lists, each inner list is (tree fitness). Input
is a list of trees, and a list of test cases."
  (mapcar (lambda (tree fitness)
            (list tree fitness))
          tree-list
          (eval-fitness (mapcar #'make-tree-lambda tree-list)
                        input-output-list)))
person Svante    schedule 19.08.2010
comment
@Svante - сейчас на работе, не могу получить код - но когда я вставляю его вот так, деревья не имеют значения. - person Paul Nathan; 19.08.2010
comment
@ Пол Натан: Ну, если я скопирую то, что вы показали, это не так. Вы пробовали его наступить? - person Svante; 20.08.2010
comment
@Svante: Я в замешательстве вне моего понимания. Мой файл находится по ссылке pastebin. ›.‹ - person Paul Nathan; 21.08.2010
comment
@ Пол Натан: Я добавил несколько комментариев в ваш pastebin. Основная проблема, похоже, в том, что вы не понимаете, для чего нужны макросы. Особенно ваш bind-trees, но также eval-fitness для меня совершенно непостижимы. - person Svante; 21.08.2010
comment
@Svante: спасибо за комментарии к моей шепелявке. Я до сих пор учусь. Я пытаюсь случайным образом построить список («дерево»), используя списки операторов и произвольное значение X, затем взять это «дерево» и построить из него анонимную функцию. Учитывая эту случайно сгенерированную функцию, я хочу запустить ее с некоторыми примерными значениями (eval-fitness) и посмотреть, соответствует ли она целевой функции. Моя следующая цель - поменять местами ветви дерева, чтобы попытаться улучшить целевую функцию. Я использую макросы для вставки дерева в шаблон (дерево лямбда (X)). - person Paul Nathan; 22.08.2010
comment
-улучшаем целевую функцию, + улучшаем случайно сгенерированную функцию - person Paul Nathan; 22.08.2010