首页 > 解决方案 > 请求有关代码风格/最佳实践的输入

问题描述

我正在尝试通过遵循 Java 中的这种实现(https://craftinginterpreters.com/control-flow.html)在 Common Lisp 中实现一种编程语言。

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

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

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

在此处输入图像描述

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

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

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

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

谢谢!

标签: coding-stylecommon-lispclos

解决方案


在类定义中定义访问器函数还可以节省一些输入,而不必使用非标准语法

如果你像这样定义一个 CLOS 类:

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

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

访问nameslot in的 slot 值的唯一方法*p*是:

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

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

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

但是,如果您为每个插槽定义 an :accessor,则可以使用作为参数给出的函数名称,:accessor而不必使用slot-valueorwith-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方法(泛型函数)特定于此类的对象。因此,您不必担心名称空间冲突。

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


推荐阅读