使用嵌套列表LISP

时间:2013-04-02 23:42:22

标签: lisp common-lisp nested-lists

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

那时候真的只是为了测试目的。虽然我真正想做的是输出最低和最左边的坐标。有什么想法吗?

3 个答案:

答案 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))会将xy绑定到12,然后2,{{1} },然后是33,最后是44。当然你可以使用更多变量/你可以使用点阵列表等。

答案 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 chapterloop spec(很容易忘记一个可能会变成的指令适合特定情况)。如果您是Lisp的新手,您可能需要查看the entire book,实际上。