我对lisp相对较新,并且对于在以下环境中使用嵌套列表的最佳方法感到好奇:
所以,我有以下功能:
(defun get-p0 (points)
(loop for (label x y) in points
; collect (list (if (> x y) (+ 2 3))))
collect (list (get-angle (first points) (second points))))
)
我称之为:
(get-p0 '((A 5 2) (B 2 3) (C 8 9)))
我一直在尝试的是获取每个坐标相对于其他坐标的角度。例如,AB,AC,BA,BC,CA,CB的角度并打印出来。我得到的输出如下:
((161.56505) (161.56505) (161.56505))
那时候真的只是为了测试目的。虽然我真正想做的是输出最低和最左边的坐标。有什么想法吗?
答案 0 :(得分:2)
我前段时间做过非常相似的运动。这看起来对您有用:
;; Define struct `point'
(defstruct point x y)
;; Define methods specializing on `point'
(defgeneric add (a b))
(defgeneric subtract (a b))
(defgeneric distance (a b))
(defgeneric projection (a))
(defmethod add ((this point) (that point))
(make-point :x (max (point-x this) (point-x that))
:y (max (point-y this) (point-y that))))
(defmethod subtract ((this point) (that point))
(make-point :x (min (point-x this) (point-x that))
:y (min (point-y this) (point-y that))))
(defmethod distance ((this point) (that point))
(let ((a (add this that)) (b (subtract this that)))
(make-point :x (- (point-x a) (point-x b))
:y (- (point-y a) (point-y b)))))
(defmethod projection ((this point))
(sqrt (+ (expt (point-x this) 2) (expt (point-y this) 2))))
;; Define helper functions
(defun angle (a b c)
(acos (/ (+ (* a a) (* b b) (- (* c c))) (* 2 a b))))
(defun radian->degree (radian) (/ (* 180 radian) pi))
;; Define struct `triangle'
(defstruct triangle
(a nil :type (or null point))
(b nil :type (or null point))
(c nil :type (or null point)))
;; Define methods specializing on `triangle'
(defgeneric angles-of (triangle))
(defgeneric sides-of (triangle))
(defgeneric points-of (triangle))
(defmethod points-of ((this triangle))
(let ((result (list (triangle-a this) (triangle-b this) (triangle-c this))))
(nconc result result)))
(defmethod sides-of ((this triangle))
(loop for (p . rest) on (points-of this)
for i from 0 below 3
collect (projection (distance p (car rest))) into result
finally (return (nconc result result))))
(defmethod angles-of ((this triangle))
(loop for (a b c) on (sides-of this)
for i from 0 below 3
collect (radian->degree (angle a b c)) into result
finally (return (nconc result result))))
;; Create some test triangle
(defvar *pythagorean-triangle*
(make-triangle :a (make-point :x 1 :y 2)
:b (make-point :x 4 :y 2)
:c (make-point :x 4 :y 6)))
;; Finally! don't forget to
(setf *print-circle* t)
;; so you can see circular lists' content
(angles-of *pythagorean-triangle*)
#1=(90.00000265626015d0 36.86989784081561d0 53.13009995842113d0 . #1#)
很少有人注意到,我在另一篇文章中看到,对表格有一些混淆
(loop for <list-like expression> in some-list ...)
这个list-like expression
通常被称为“解构绑定”。它是一种有限的模式匹配设施。实际上,这是一种模式,它将您在模式中定义的符号映射到您迭代的列表中找到的任何值。
因此,例如,(loop for (x y) on '(1 2 3 4))
会将x
和y
绑定到1
和2
,然后2
,{{1} },然后是3
,3
,最后是4
,4
。当然你可以使用更多变量/你可以使用点阵列表等。
答案 1 :(得分:1)
您使用for (x y z) in list
形式正确绑定每次迭代的值。但是当您在下一行中进行收集时,您将从list
的开头处获取值。这个值永远不会改变循环的评估。
您应该将代码更改为:
(defun get-p0 (points)
(loop
for (label x y) in points
collect (list (get-angle x y))))
答案 2 :(得分:1)
如果我正确理解了您的目标,您希望使用'((A 5 2) (B 2 3) (C 8 9))
之类的列表并返回(2 2)
之类的内容(点a的A y
为2,而B的点数为{{ 1}}的2,这些是最低的坐标。我会做类似
x
(loop for (_l x y) in lst
minimizing y into min-y minimizing x into min-x
finally (return (list min-x min-y)))
是一个深层而强大的构造,所以我建议你仔细阅读relevant PCL chapter和loop
spec(很容易忘记一个可能会变成的指令适合特定情况)。如果您是Lisp的新手,您可能需要查看the entire book,实际上。