CLOS 中的 with-slots 宏的教学示例是什么?
What is a didatic example of the with-slots macro in CLOS?
Common Lisp HyperSpec covers with-slots
宏。但是,这个例子很难掌握。
是否有关于它的更简单、更具教学意义的示例?
是的。 2003年的这个(伟大的)tutorial有一个几何领域的好。
创建一个 class 来表示 3 维点:
(defclass point ()
(x y z))
创建一个变量来实例化 class 和一个函数来设置值:
(defvar my-point
(make-instance 'point))
(defun set-point-values (point x y z)
(setf (slot-value point 'x) x
(slot-value point 'y) y
(slot-value point 'z) z))
在 REPL 中,执行:
CL-USER 17 > (set-point-values my-point 3 4 12)
12
现在,想一想compute the distance点之间的函数。一种蛮力方式是:
(defun brute-force-distance-from-origin (point)
(let ((x (slot-value point 'x))
(y (slot-value point 'y))
(z (slot-value point 'z)))
(sqrt (+ (* x x)
(* y y)
(* z z)))))
使用 with-slots
宏:
(defun distance-from-origin (point)
(with-slots (x y z) point (sqrt (+ (* x x)
(* y y)
(* z z)))))
调用 REPL 中的函数按预期工作:
CL-USER> (distance-from-origin my-point)
13.0
首先要更好地理解with-slots, one should look into defclass。
No reader or writer functions are defined by default; their generation must be explicitly requested. However, slots can always be accessed using slot-value.
这意味着,除非有特殊要求,defclass
不要为插槽创建任何访问器:
> (defclass point ()
(x y))
(let ((new-point (make-instance 'point)))
(setf (point-x new-point) 1))
Error: The function (COMMON-LISP:SETF COMMON-LISP-USER::POINT-X) is undefined.
在这种情况下,必须使用 slot-value 函数来访问或修改槽值。
(defclass point ()
(x y))
(let ((new-point (make-instance 'point)))
(setf (slot-value new-point 'x) 1))
显然,当有多个slot需要更新时,代码会变得有点繁琐:
(defmethod translate ((point-instance point) delta-x delta-y)
(setf (slot-value point-instance 'x)
(+ (slot-value point-instance 'x) delta-x))
(setf (slot-value point-instance 'y)
(+ (slot-value point-instance 'y) delta-y)))
因此,with-slots macro 可以使代码更易于阅读:
(defmethod translate ((point-instance point) delta-x delta-y)
(with-slots (x y) point-instance
(setf x (+ x delta-x))
(setf y (+ y delta-y))))
Common Lisp HyperSpec covers with-slots
宏。但是,这个例子很难掌握。
是否有关于它的更简单、更具教学意义的示例?
是的。 2003年的这个(伟大的)tutorial有一个几何领域的好。
创建一个 class 来表示 3 维点:
(defclass point ()
(x y z))
创建一个变量来实例化 class 和一个函数来设置值:
(defvar my-point
(make-instance 'point))
(defun set-point-values (point x y z)
(setf (slot-value point 'x) x
(slot-value point 'y) y
(slot-value point 'z) z))
在 REPL 中,执行:
CL-USER 17 > (set-point-values my-point 3 4 12)
12
现在,想一想compute the distance点之间的函数。一种蛮力方式是:
(defun brute-force-distance-from-origin (point)
(let ((x (slot-value point 'x))
(y (slot-value point 'y))
(z (slot-value point 'z)))
(sqrt (+ (* x x)
(* y y)
(* z z)))))
使用 with-slots
宏:
(defun distance-from-origin (point)
(with-slots (x y z) point (sqrt (+ (* x x)
(* y y)
(* z z)))))
调用 REPL 中的函数按预期工作:
CL-USER> (distance-from-origin my-point)
13.0
首先要更好地理解with-slots, one should look into defclass。
No reader or writer functions are defined by default; their generation must be explicitly requested. However, slots can always be accessed using slot-value.
这意味着,除非有特殊要求,defclass
不要为插槽创建任何访问器:
> (defclass point ()
(x y))
(let ((new-point (make-instance 'point)))
(setf (point-x new-point) 1))
Error: The function (COMMON-LISP:SETF COMMON-LISP-USER::POINT-X) is undefined.
在这种情况下,必须使用 slot-value 函数来访问或修改槽值。
(defclass point ()
(x y))
(let ((new-point (make-instance 'point)))
(setf (slot-value new-point 'x) 1))
显然,当有多个slot需要更新时,代码会变得有点繁琐:
(defmethod translate ((point-instance point) delta-x delta-y)
(setf (slot-value point-instance 'x)
(+ (slot-value point-instance 'x) delta-x))
(setf (slot-value point-instance 'y)
(+ (slot-value point-instance 'y) delta-y)))
因此,with-slots macro 可以使代码更易于阅读:
(defmethod translate ((point-instance point) delta-x delta-y)
(with-slots (x y) point-instance
(setf x (+ x delta-x))
(setf y (+ y delta-y))))