我想按照这个在Java中的实现,用Common Lisp实现一种编程语言(https:/craftinginterpreters.comcontrol-flow.html。).
其中有一点是非常麻烦的,就是到处都是大量的槽值。
固然我可以在每个函数中添加一行with-slots,但这也是重复的,而且鉴于我的符号不是:use,而是我用包来引用,因为有很多模块的符号,我不想失去它们从哪里来的踪迹,即使with-slots也需要完整的限定名。所有这些在我看来都是非常糟糕的代码味道。
我上网查了一下,发现rutils。有了它的@object.slot接入器,我成功地清理了我的代码。看看最后的提交 https:/github.comAlbertoEAFcl-loxcommit84c0d62bf29bff9a2e0e77042a9108c168542b96?diff=split。 节选。
(我可以粘贴代码,但所有的代码都在那个仓库里,我想显示不同的亮点)
它不仅去掉了一些字符,更重要的是,少了一层深度(槽值调用)和小括号的考虑--这帮了很大的忙,但对于琐碎的函数。
当我有很多很多的符号名时,情况就变得更糟了,我无法再全部导出,因为我开始在符号中出现冲突。
你们能不能给我一些代码上的意见?现在看起来好多了,但我很好奇,如果有更好的方法去做?
谢谢!我正在尝试实现一个编程。
如果你定义了这样一个CLOS类。
(defclass person ()
((name
:initarg :name)))
(defparameter *p* (make-instance 'person
:name "John"))
那么访问槽值的唯一方法就是: name
槽中 *p*
是。
(slot-value *p* 'name)
;; "John"
(with-slots (name) *p*
name)
;; "John"
(with-slots ((nm name)) *p*
nm)
;; "John"
但如果你为每个槽定义一个 :accessor
你可以使用函数namegiven作为参数的 :accessor
而不必使用 slot-value
或 with-slots
读取和变异它(setf
-可以!)。)
(defclass person ()
((name
:initarg :name
:accessor nm)))
(nm *p*)
;; "John"
(setf (nm *p*) "Doe")
;; "Doe"
(nm *p*)
;; "Doe"
然而,惯例是将槽名也作为 :accessor
方法的名称。
(defclass person ()
((name
:initarg :name
:accessor name))) ;; but better use the slot name as accessor
(name *p*)
;; "John"
(setf (name *p*) "Doe")
(name *p*)
;; "Doe"
方法名称: :accessor
方法(通用函数)是针对这个类的对象的。因此你不需要担心名空间冲突。
(defclass house ()
((address
:initarg :address
:accessor addr)))
;; you cannot use `address` because it is already occupied
;; by a system's function/symbol -> see under `(describe 'address)`
(defparameter *h* (make-instance 'house :address "Bakerstreet 1"))
(name *h*)
;; EVAL: undefined function name OR:
;; NO-APPLICABLE-METHOD error (in the case
;; that other classes exist with a `name` accessor method.
(addr *h*)
;; "Bakerstreet 1"
(addr *p*)
;; *** - NO-APPLICABLE-METHOD: When calling #<STANDARD-GENERIC-FUNCTION ADDR>
;; with arguments (#<PERSON #x1B06B79E>), no method is applicable.
;;