请求有关代码风格/最佳实践的输入

Request input regarding code style / best practices

我正在尝试按照 Java (https://craftinginterpreters.com/control-flow.html) 中的此实现来用 Common Lisp 实现编程语言。

真正令人烦恼的事情之一是到处都有大量槽值。

当然我可以在每个带有槽的函数中添加一行,但这也是重复的,并且考虑到我的符号没有 :used 但我通过包引用它们,因为有很多符号来自许多模块,我不想忘记它们的来源,即使 with-slots 也需要完整的限定名称。所有这些在我看来都是非常糟糕的代码味道。

我用谷歌搜索并找到了金红石。通过它的 @object.slot 访问器,我设法极大地清理了我的代码。看看最后一次提交 https://github.com/AlbertoEAF/cl-lox/commit/84c0d62bf29bff9a2e0e77042a9108c168542b96?diff=split 摘录:

(我可以粘贴代码,但所有代码都可以在那个 repo 上找到,我想展示差异亮点)

它不仅删除了一些字符,更重要的是,减少了一层深度(槽值调用)和需要考虑的括号 - 这对琐碎的函数有很大帮助。

当我有很多符号名称并且无法再将它们全部导出时,情况会变得更糟,因为我开始在符号中发生冲突。

你们能给我输入代码吗?现在看起来好多了,但我很好奇是否有更好的方法?

谢谢!

在 class 定义中定义访问器函数还可以节省您的输入时间,同时不必使用非标准语法

如果您这样定义 CLOS class:

(defclass person ()
  ((name
    :initarg :name)))

(defparameter *p* (make-instance 'person 
                     :name "John"))

访问 *p*name 插槽值的唯一方法是:

(slot-value *p* 'name)
;; "John"

(with-slots (name) *p*
  name)
;; "John"

(with-slots ((nm name)) *p*
  nm)
;; "John"

但是如果你为每个插槽定义一个:accessor,你可以使用函数名 作为 :accessor 的参数给出,不必使用 slot-valuewith-slots,以 访问并改变它(setf-able!)。

(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方法(泛型函数)是针对对象的 这个class。因此,您不必担心名称-space 冲突。

(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.
;;