Разница между let * и set? в Common Lisp - PullRequest
3 голосов
/ 19 августа 2010

Я работаю над проектом в области генетического программирования.

У меня есть настройка функции / макроса, которая при оценке в форме 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, но для меня это не имеет смысла.

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

--- edit: вытащил мой код и поместил весь файл в папку --- --- 1017 *

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

(defun generate-sample () (пусть ((веточки (деревья 2))) (пусть ((привязки деревьев (ветки деревьев связывания))) (let ((оцененные деревья (привязки деревьев по eval-пригодности)))
(список веток деревьев-привязок оцененных деревьев)))))

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

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

1 Ответ

3 голосов
/ 19 августа 2010

(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)))
...