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