gpt4 book ai didi

common-lisp - 从使用的外部包访问 CLOS 对象槽

转载 作者:行者123 更新时间:2023-12-04 16:51:10 31 4
gpt4 key购买 nike

我正在学习构建我的 CL 程序,现在在使用大型包进行编程时无法使用 CLOS。

包.lisp

(defpackage :my-project.a
(:use :cl)
(:export
create-my-object
my-object
; EXPORT SINGLE SLOTS?
my-slot-1
; my-slot-...
; my-slot-n

; OR EXPORT ALL ACCESSOR-FUNCTIONS?
my-slot-1-accessor
; my-slot-n-accessor...
))

(defpackage :my-project.b
(:use :cl :my-project.a)
(:export print-object-slot))

src.lisp

虽然类 MY-OBJECT 是在 MY-PROJECT.A 中定义的
(in-package :my-project.a)

(defclass my-object ()
((my-slot-1 :accessor my-slot-1-accessor :initarg :my-slot-1)
;... more slots
; (my-slot-2 :accessor my-slot-2-accessor :initarg :my-slot-2)
; (my-slot-n :accessor my-slot-n-accessor :initarg :my-slot-n)
))

作为对象的一些 CREATOR 函数
(defun create-my-object ()
(make-instance 'my-object
:my-slot-1 "string"
;; further slots...
))

有一些功能,例如MY-PROJECT.B 包中的 PRINT-OBJECT,
它应该处理从函数实例化的对象
(in-package :my-project.b)

(defun print-object-slot (slot-name object)
(format nil "slot-value: ~a" (SLOT-VALUE object slot-name)))

问题

虽然执行以下代码不起作用
(in-package :my-project.b)

(describe 'my-object) ; works

(print-object-slot
'my-slot-1 ; while this works: 'my-project.a:my-slot-1 [if slot is exported]
(create-my-object))

;; ==> slot MY-PROJECT.B:MY-SLOT-1 is missing from the object
;; MY-PROJECT.A:MY-OBJECT

要以编程方式访问我的插槽,在这种情况下,我需要将原始包名称与插槽名称合并,以从外部类获取/设置插槽......

我的理解

来自 CLOS 对象的访问器函数是通用函数,属于包,它们已通过 DEFCLASS 定义,在本例中为:MY-PROJECT.A

作者 (use-package :my-project.a)在 MY-PROJECT.B 中,导出的符号被导入,这就是 DESCRIBE 起作用的原因。但不包括通用插槽访问器功能的符号。
  • 考虑:
    不应计划程序的体系结构来共享/导出对象和插槽访问。它不适用于批量导入/导出插槽/访问器功能。
  • 考虑:
    您可以构建一个自定义函数,该函数通过其包中的 slot-accessor-function 获取/设置插槽,因此只有一个接口(interface)函数可以导出?

  • 我的问题:

    这种处理外部 CLOS 对象的方式似乎不是可行的方法。
    如何以理智的方式导出/导入这些访问器功能,而不需要手动列出每个插槽?

    编辑/解决方案

    我的术语和插槽与访问器功能的使用是导致此问题的原因( 非常感谢@RainerJoswig 清除术语)。

    我没有使用导出版本的 MY-SLOT-1-ACCESSOR 函数,它可以按预期工作,但是如果我想访问所有其他外部包中的所有插槽,则需要我“批量导出”它们. @sds 很好地展示了如何做到这一点,并指出了我的方法的一般问题 .非常感谢 :)

    在我看来,我希望只导出对象并获得对所有内部函数的完全访问权限。但这对 CLOS 来说是错误的,因为符号和方法不共享与类/对象的直接绑定(bind),我必须适应更好的代码组织。

    最佳答案

    术语

    这个问题并没有明确插槽、插槽名称和插槽访问器功能之间的区别。将插槽名称和访问器函数混为一谈并不是一个好主意。你应该清楚什么是什么。

    (defpackage "GUI"
    (:use "CL")
    (:export
    ;; class
    window
    window-screen
    window-width
    window-height))

    (defclass window ()
    ((screen :accessor window-screen :initarg :screen)
    (width :accessor window-width :initarg :width :initform 640)
    (height :accessor window-height :initarg :height :initform 400)))

    现在 screen是插槽名称和 window-screen是一个存取函数。

    插槽名称只是一个符号。您可以为此使用任何符号。例如你也可以写(只是一个随机的例子,不要使用):
    (defpackage "SLOTS" (:use))
    (defpackage "AC" (:use)
    (:export
    "WINDOW-SCREEN"
    "WINDOW-WIDTH"
    "WINDOW-HEIGHT"))

    (defclass window ()
    ((slots::screen :accessor ac:window-screen :initarg :screen)
    (slots::width :accessor ac:window-width :initarg :width :initform 640)
    (slots::height :accessor ac:window-height :initarg :height :initform 400)))

    以上将使用包中的插槽名称 slots和封装中的访问器 ac .

    访问器是一个通用函数。

    所以,当你写:
    (defun foo (instance slot-name)
    ...)

    我希望 slot-name 是一个符号,而不是访问器函数。
    (defun foo (instance accessor)
    ...)

    对于上面我希望访问器是一个函数,而不是一个符号。

    如果你真的想把区别说清楚,你可以写方法:
    (defmethod foo (instance (path symbol))
    (slot-value instance path))

    (defmethod foo (instance (path function))
    (funcall function instance))

    导出什么?

    通常我会在包中导出访问器名称,而不是插槽名称。

    进口?

    但通常我什至不会导入包:
    (defpackage "GUI-GAME"
    (:use "CL"))

    以上包不导入包 gui .可以,但这里不行。
    (defmethod describe-window ((w gui:window))
    (format t "~% Window width:~a height:~a"
    (gui:window-width w)
    (gui:window-width h)))

    优点是我在源代码中看到了两件事:
  • gui:window被导出,因此是包接口(interface)的一部分
  • gui:window实际上是来自包gui而且没有名字
    与其他符号冲突。

  • 只需使用类和访问器函数的符号,加上它们的包名。

    关于common-lisp - 从使用的外部包访问 CLOS 对象槽,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41575183/

    31 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com