Lisp 让康德的时候有人写信吗?

Lisp 让康德的时候有人写信吗?,lisp,common-lisp,sbcl,Lisp,Common Lisp,Sbcl,我在想一个带旋转的康德 (let ((a 0)) (let* ((result nil)) (tagbody (let ((b1 (+ 0 a))) (when (eq b1 1) (print "1") (setf result b1) (go finish))) (let ((b2 (+ 0 a))) (when (eq b2 2)

我在想一个带旋转的康德

(let ((a 0))
  (let* ((result nil))
    (tagbody
       (let ((b1 (+ 0 a)))
         (when (eq b1 1)
           (print "1")
           (setf result b1)
           (go finish)))
       (let ((b2 (+ 0 a)))
         (when (eq b2 2)
           (print "2")
           (setf result b2)
           (go finish)))
       (when T
         (print "else")
         (setf result a))
       (format t "=== ~A~%" a)
     finish)
    result))
其中
测试表单包装在
let
中时。一方面,这似乎适合我正在研究的一个问题,但也似乎过于复杂。可以用宏来简化吗?如果我有很多测试表格,那么简化它的最佳方法是什么

尝试这样做的部分问题是将let块仅限于一个测试表单及其主体

但我想知道我是否走错了路。玩一个想象中的when-let变体意味着沿着这条路走下去没有任何好处

试水条件 使用cond的版本似乎更紧凑

(let ((a 3))
  (let* ((b1 (+ 0 a))
         (b2 (+ 0 a)))
    (cond
      ((eq b1 1)
       (print "1")
       b1)
      ((eq b2 2)
       (print "2")
       b2)
      (T (print "else")
         a))))

所有这些都归结为let*中定义的变量,在实际示例中,将使用这些变量来避免两次计算相同的值,并提高可读性。我该怎么办?

使用macrolet是目前为止最好的解决方案。这使我能够绕过when let的限制,并且不是let表单中的所有bindin都必须计算为true

(let ((a 3))
  (let ((result nil))
    (macrolet ((ret-go (res)
                 `(progn
                    (setf result ,res)
                    (go finish))))
      (tagbody
         (let ((b1 (+ 0 a)))
           (when (eq b1 1)
             (print "1")
             (ret-go b1)))
         (let ((b2 (+ 0 a)))
           (when (eq b2 2)
             (print "2")
             (ret-go b2)))
         (when T
           (print "else")
           (setf result a))
         (format t "=== ~A~%" a)
       finish)
      result)))

我更喜欢从块和返回值的角度来考虑,而不是使用goto和变量。如果确实需要单独的let绑定变量及其自己的作用域:

(prog ((a 0))
  (let ((b1 (+ 0 a)))
    (when (eql b1 1)
      (print "1")
      (return b1)))
  (let ((b2 (+ 0 a)))
    (when (eql b2 2)
      (print "2")
      (return b2)))
  (return
    (progn
      (print "else")
      (return a))))

现在有人这样做了。我希望它与
cond
兼容,这就带来了一个问题:如果您希望绑定子句与

(cond/binding
  ...
  ((var expr) <use var>)
  ...)
调用
car
或绑定
car
?若要使其正常工作,则需要在这种情况下绑定一个无用的变量:

(cond/binding
  ...
  ((useless (car x)) <useless not used here>)
  ...)
请注意,
bind
在语法上很神奇(因此这意味着您不能调用名为
bind
的函数,但这没关系,因为我已经在中使用了
bind
作为关键字

宏也努力(好吧,很努力,因为我基本上只是输入了它,它没有测试)实际表现得像
cond
:例如,返回多个值

因此:

(cond/binding
  ((f x y z) t)
  ((bind x 3) (print x) (values x t))
  (t (values nil nil))
  (1))
扩展到

(block #:cond/binding
  (when (f x y z)
    (return-from #:cond/binding (progn t)))
  (let ((x 3))
    (when x
      (return-from #:cond/binding
        (progn (print x) (values x t)))))
  (when t
    (return-from #:cond/binding (progn (values nil nil))))
  (let ((r 1))
    (when r
      (return-from #:cond/binding r))))
(其中所有块都是同一块)

因此,这里:

(defmacro cond/binding (&body clauses)
  ;; Like COND but it can bind variables.  All clauses are (should be)
  ;; like COND, except that a clause of the form ((bind var <expr>)
  ;; ...) will bind a variable.  Note that bind has to be literally
  ;; the symbol BIND: it's magic in the syntax.
  (let ((bn (make-symbol "COND/BINDING")))
    `(block ,bn
       ,@(mapcar
          (lambda (clause)
            (unless (consp clause)
              (error "bad clause ~S" clause))
                (case (length clause)
                  (1
                   `(let ((r ,(car clause)))
                      (when r (return-from ,bn r))))
                  (otherwise
                   (destructuring-bind (test/binding &body forms) clause
                     (typecase test/binding
                       (cons
                        (case (car test/binding)
                          ((bind)
                           (unless (and (= (length test/binding) 3)
                                        (symbolp (second test/binding)))
                             (error "bad binding clause ~S" test/binding))
                           (destructuring-bind (var expr) (rest test/binding)
                             `(let ((,var ,expr))
                                (when ,var
                                  (return-from ,bn
                                    (progn ,@forms))))))
                          (otherwise
                           `(when ,test/binding
                              (return-from ,bn
                                (progn ,@forms))))))
                       (t
                        `(when ,test/binding
                           (return-from ,bn
                             (progn ,@forms)))))))))
          clauses))))
(定义宏条件/绑定(&body子句)
;与COND类似,但它可以绑定变量。所有子句都是(应该是)
;与COND类似,但形式为((bind var)的子句除外
;;;…)将绑定一个变量。请注意,绑定必须是字面意义上的
符号绑定:它的语法很神奇。
(让((bn(使符号“COND/BINDING”))
`(b座)
,@(地图车
(第条)
(除非(消费条款)
(错误“bad子句~S”子句)
(案例(长度条款)
(1
`(出租((r,(car条款)))
(当r(从,bn r)返回时)
(否则
(解构绑定(测试/绑定和实体形式)条款
(打字机测试/装订)
(缺点
(案例(汽车测试/绑定)
((绑定)
(除非(和(=(长度测试/绑定)3)
(symbolp(第二次测试/绑定)))
(错误“坏约束条款”测试/约束)
(解构绑定(var-expr)(rest测试/绑定)
`(let(,var,expr))
(何时,var
(英国国民银行返回)
(progn,@forms(()()))
(否则
`(何时测试/绑定)
(英国国民银行返回)
(progn,@forms(()()))
(t
`(何时测试/绑定)
(英国国民银行返回)
(progn,@forms(()()())())))
条款))

买主注意事项。

如果我正确理解您的问题,那么您可以使用
,并依赖于这样一个事实,即如果条件不正确,当
被计算为
nil
,例如

(定义示例(a)
(或
(让((b1(+0 a)))
(当(eql b1 1)
(打印“1”)
b1))
(让((b2(+0 a)))
(当(eql b2 2)
(打印“2”)
b2))
(项目
(打印“其他”)
a) ))

when_let是一个流行的宏,恰好在Alexandria库中定义(可能还有很多其他宏).when-let设置返回的结果,然后跳转到标记体的结尾吗?听起来像是你建议编写我自己版本的when-let.numbers需要与EQL或=.EQ进行比较。EQ不按值进行比较,而是按对象标识进行比较。或者使用模式匹配库,如trivia/optima.Ouch!因此应该为尊敬的提到。我已经在谷歌上搜索了caveat emptor,我明白你的意思。我没有想到需要返回多个值。我只是在尝试打破常规,尝试解析和遍历一些不寻常的数据结构的不同可能性。你的答案比我使用macrolet的建议要好得多。谢谢非常好。”(也就是说,let的主体是一个隐式progn)。”特殊运算符let的Hyperspec,let*。由于某种原因,我现在忘记了,我对“else”部分有问题,所以我朝错误的方向寻找。
(block #:cond/binding
  (when (f x y z)
    (return-from #:cond/binding (progn t)))
  (let ((x 3))
    (when x
      (return-from #:cond/binding
        (progn (print x) (values x t)))))
  (when t
    (return-from #:cond/binding (progn (values nil nil))))
  (let ((r 1))
    (when r
      (return-from #:cond/binding r))))
(defmacro cond/binding (&body clauses)
  ;; Like COND but it can bind variables.  All clauses are (should be)
  ;; like COND, except that a clause of the form ((bind var <expr>)
  ;; ...) will bind a variable.  Note that bind has to be literally
  ;; the symbol BIND: it's magic in the syntax.
  (let ((bn (make-symbol "COND/BINDING")))
    `(block ,bn
       ,@(mapcar
          (lambda (clause)
            (unless (consp clause)
              (error "bad clause ~S" clause))
                (case (length clause)
                  (1
                   `(let ((r ,(car clause)))
                      (when r (return-from ,bn r))))
                  (otherwise
                   (destructuring-bind (test/binding &body forms) clause
                     (typecase test/binding
                       (cons
                        (case (car test/binding)
                          ((bind)
                           (unless (and (= (length test/binding) 3)
                                        (symbolp (second test/binding)))
                             (error "bad binding clause ~S" test/binding))
                           (destructuring-bind (var expr) (rest test/binding)
                             `(let ((,var ,expr))
                                (when ,var
                                  (return-from ,bn
                                    (progn ,@forms))))))
                          (otherwise
                           `(when ,test/binding
                              (return-from ,bn
                                (progn ,@forms))))))
                       (t
                        `(when ,test/binding
                           (return-from ,bn
                             (progn ,@forms)))))))))
          clauses))))