let *和set之间的区别?在Common Lisp中

时间:2010-08-19 05:08:12

标签: macros lisp common-lisp

我正在从事遗传编程爱好项目。

我有一个函数/宏设置,当以setq / setf形式计算时,会生成一个类似于此的列表。

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

然后通过战略性使用函数/宏将它绑定到lambda函数#<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)))

但是,当我将其放在let表单中时,我会得到EVAL: trees has no value。我怀疑与SETF相比,宏扩展在LET中没有完全执行,但这对我来说没有意义。

这个问题的原因是什么?

---编辑:猛拉我的代码并将整个文件放入pastebin ---

假设我决定setq不会为我做这个并且我写了一个简单的函数来执行它:

(defun generate-sample()       (让((twiggs(make-trees 2)))     (让((树绑定(bind-trees twiggs)))       (let((evaluate-trees(eval-fitness tree-bindings)))
        (列出twiggs树绑定评估树)))))

这会导致...帮助文件错误消息(??!?)...和“eval:variable twiggs没有值”爆炸,这源于SLIME检查中的绑定树定义。

我有理由相信我已经完全收回了我的宏。 http://pastebin.org/673619

1 个答案:

答案 0 :(得分:3)

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

Letsetq完全不同。 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)))

最后一行也是虚假的。如果这些名字受到约束,那就会 返回一个元素的列表,这将是评估的结果 功能treestree-bindingsevaluated-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)))