简体   繁体   English

在 let 绑定列表中获取值(Common Lisp)

[英]Getting value in a let-binded list (Common Lisp)

In below situation, I want to get same results for a and (car b) like (10 10) .在下面的情况下,我想为a(car b)获得相同的结果,例如(10 10) But just symbol A is shown as a result of (car b) .但是只有符号A显示为(car b)的结果。 Can we get 10 with like (something (car b)) code?我们可以用类似的(something (car b))代码得到10吗?

(let* ((a 10)
       (b '(a)))
  (list a (car b))) ; (10 A)
  ;; Hoping to get (10 10) with (list a (something (car b)))

I also tried below ones but couldn't get the answer.我也试过下面的但无法得到答案。

(let* ((a 10)
       (b '(a))
       (c `(,a)))
  (list a ; 10
        'a ; A
        (car b) ; A
        (eq (car b) 'a) ; T
        (car c) ; 10
        ;; (eval 'a) ; Error - The variable A is unbound.
        ;; (symbol-value (car b)) ; Error - The variable A is unbound.
        ))

My motivation is to make symbols and params lists with let like below.我的动机是像下面这样用let制作symbolsparams列表。 But the part of foo is not working as I expected now.但是foo的部分现在没有像我预期的那样工作。 I believe above question will solve (or help) this also.我相信上述问题也会解决(或帮助)这个问题。 (This part is not question) (这部分不是问题)

(defmacro my-let (binds &body body)
  `(let ((symbols (mapcar #'car ',binds))
         (params (mapcar #'(lambda (x) (eval (cadr x))) ',binds))) ; I may need to modify here
     (let ,binds
       ,@body)))

(defun foo (bar)
  (my-let ((b bar))
    (list symbols params)))

(foo "baz") ; Error - The variable BAR is unbound.

[I wrote this mostly before coredump's answer was posted and then forgot about it. [我主要是在 coredump 的答案发布之前写的,然后忘记了。 I think that answer is probably the one you want but perhaps this is worth reading as well.]我认为答案可能是你想要的,但也许这也值得一读。]

You can't retrieve the values of lexically-bound variables from their names.您无法从名称中检索词法绑定变量的值。 However, you can (as I think you are trying to do) write macros which bind variables and then remember the names of the bindings.但是,您可以(正如我认为您正在尝试做的那样)编写绑定变量的宏,然后记住绑定的名称。 Here are two, both of which introduce a local function called valof which lets you get at the value of a binding by name.这里有两个,它们都引入了一个名为valof的本地 function,它可以让您通过名称获取绑定的值。 Neither are completely correct: see the end for why.两者都不完全正确:请参阅结尾了解原因。

For both of these macros the trick is to maintain a secret association list between names and values.对于这两个宏,诀窍是在名称和值之间维护一个秘密关联列表。

(defmacro let/names (bindings &body forms)
  (let ((<map> (make-symbol "MAP")))
    `(let ,bindings
       (let ((,<map> (list ,@(mapcar (lambda (b)
                                       (etypecase b
                                         (symbol
                                          `(cons ',b ,b))
                                         (cons
                                          `(cons ',(car b) ,(car b)))))
                                     bindings))))
         (flet ((valof (s)
                  (let ((m (assoc s ,<map>)))
                    (if m
                        (values (cdr m) t)
                      (values nil nil)))))
           ,@forms)))))

Here is what the expansion of this looks like (here *print-circle* is true so you can see that the gensymed name is used):这是扩展后的样子(此处*print-circle*为真,因此您可以看到使用了 gensymed 名称):

(let/names ((a 1))
  (valof 'a))
 -> (let ((a 1))
      (let ((#1=#:map (list (cons 'a a))))
        (flet ((valof (s)
                 (let ((m (assoc s #1#)))
                   (if m (values (cdr m) t) (values nil nil)))))
          (valof 'a))))

Now, for instance:现在,例如:

> (let/names ((a 1))
    (valof 'a))
1
t

> (let/names ((a 1))
    (valof 'b))
nil
nil

But this macro is not actually really correct:但这个宏实际上并不正确:

> (let/names ((a 1))
    (setf a 2)
    (valof 'a))
1
t

To deal with this problem the trick is to build a bunch of little functions which access the values of bindings.解决这个问题的诀窍是构建一堆访问绑定值的小函数。 While doing that we can also allow assignment: mutation of the bindings.在这样做的同时,我们还可以允许赋值:绑定的突变。

(defmacro let/names (bindings &body forms)
  (let ((<map> (make-symbol "MAP")))
    `(let ,bindings
       (let ((,<map> (list ,@(mapcar (lambda (b)
                                       (etypecase b
                                         (symbol
                                          `(cons ',b
                                                 (lambda (&optional (v nil vp))
                                                   (if vp
                                                       (setf ,b v)
                                                     ,b))))
                                         (cons
                                          `(cons ',(car b)
                                                 (lambda (&optional (v nil vp))
                                                   (if vp
                                                       (setf ,(car b) v)
                                                     ,(car b)))))))
                                     bindings))))
         (flet ((valof (s)
                  (let ((m (assoc s ,<map>)))
                    (if m
                        (values (funcall (cdr m)) t)
                      (values nil nil))))
                ((setf valof) (n s)
                  (let ((m (assoc s ,<map>)))
                    (unless m
                      (error "~S unbound" s))
                    (funcall (cdr m) n))))
           ,@forms)))))

Here, again, is what the expansion looks like (much more complicated now):这又是扩展的样子(现在要复杂得多):

(let/names ((a 1))
  (valof 'a))
 -> (let ((a 1))
      (let ((#1=#:map
             (list (cons 'a
                         (lambda (&optional (v nil vp))
                           (if vp (setf a v) a))))))
        (flet ((valof (s)
                 (let ((m (assoc s #1#)))
                   (if m (values (funcall (cdr m)) t) (values nil nil))))
               ((setf valof) (n s)
                 (let ((m (assoc s #1#)))
                   (unless m (error "~S unbound" s))
                   (funcall (cdr m) n))))
          (valof 'a))))

Now everything is better:现在一切都更好了:

> (let/names ((a 1))
    (valof 'a))
1
t

> (let/names ((a 1))
    (valof 'b))
nil
nil

> (let/names ((a 1))
    (setf a 2)
    (valof 'a))
2
t

> (let/names ((a 1))
    (setf (valof 'a) 3)
    a)
3

Why neither of these macros is completely right .为什么这两个宏都不是完全正确的 Neither macro deals with declarations properly: in a case like这两个宏都没有正确处理声明:在这样的情况下

(let/names ((a 1))
  (declare (type fixnum a))
  ...)

The declaration will end up in the wrong place.声明最终会出现在错误的地方。 Dealing with this requires 'lifting' declarations to the right place, which is easy to do but I'm not going to make these even more complicated than they already are.处理这个问题需要将声明“提升”到正确的位置,这很容易做到,但我不会让它们变得比现在更复杂。

Would something like this solve your problem?这样的事情会解决你的问题吗?

(defmacro my-let ((&rest bindings) &body body)
  `(let ,bindings
     (let ((symbols ',(mapcar #'car bindings))
           (values (list ,@(mapcar #'car bindings))))
       ,@body)))
                                                                                                                                                                                                                                              
((lambda (bar)
   (my-let ((b bar))
     (list symbols values)))
 "baz")

((B) ("baz"))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM