为说明起见,这是一个不变的结构和一个更新它的函数:
(struct timeseries (variable observations) #:transparent)
(define (add-observation ts t v)
(struct-copy timeseries ts
[observations (conj (timeseries-observations ts) `(,t ,v))]))
我的问题是:如果我创建一个继承自timeseries
的结构,那么add-observation
将返回一个timeseries
结构,而不是其传递类型的结构。如何更新结构并保留其类型?
顺便说一句,如果上面的代码不是Racket中的工作方式,请让我知道常规方式。我没有在Racket库中找到像struct-copy
这样的函数,但是保留了原始结构的类型,这一事实使我怀疑我正在以错误的方式进行操作。是否有一些普通的方法可以实现相同的目的,而不会遇到返回与您开始时不同类型的结构的问题?
答案 0 :(得分:2)
不幸的是,这是struct-copy
的众所周知的局限性之一,其中大部分是由Sam Tobin-Hochstadt恰当地described实施的,因为它“将结构的某些位同质地粘贴在一起” (而不是复制结构的底层概念),并且是reason的一部分,即“ struct-copy
是绝望的,如果不对结构的工作方式进行重大更改就无法解决。” Matthias Felleisen described将此视为“我们世界的致命弱点”。球拍社区肯定有改善这种状况的愿望,但是出于多种原因,这似乎令人生畏。我不知道有人在积极从事这项工作,有原则的解决方案看起来是一个悬而未决的问题。
在很多方面,结构对于球拍来说都是非常基本的。从概念上讲,Racket中的每个值都可以是某种结构类型的实例,尽管实际上,运行时系统对某些内置程序具有专门的表示形式。实际上,我认为正在进行的在Racket实现中用Chez Scheme替换C的工作可能会将结构用于旧式Racket VM中内置的某些内容。这是可能的,因为结构提供了强大的封装功能,尤其是通过inspectors。改进结构的工作方式本质上将影响整个Racket并涉及许多不同的考虑因素,尤其是在向后兼容方面。
以下是进一步了解该问题的一些提示:
struct
如何在保持向后兼容性的同时开始提供更多静态信息。 This thread指出了struct-copy
的另一个局限性,其中包括Alexis的总结:
…
struct-copy
不可修复地损坏,如果没有它就无法修复 Racket结构系统的根本变化。即,它具有 使用struct时C ++程序员熟悉的“切片”问题 继承,以及从中综合字段访问器的方式 提供的字段名称不卫生,很容易受阻。
好消息是,尽管想出解决一般情况的正确方法很困难,但是Racket的“语言即图书馆”方法使所有程序员和库作者可以在自己的代码中尝试不同的方法。有各种Racket软件包可帮助您进行功能更新和其他功能。 Alexis的struct-update
提供了一个宏来合成timeseries-observations-update
之类的函数。杰伊·麦卡锡(Jay McCarthy)还对enhancements to struct的库代码进行了实验。您还可以实施针对特定用例的解决方案,范围从实施一致的copy
方法(使用racket/generic
或racket/class
)到创建可以更自然地使用的领域特定语言表达您的问题领域。 This mailing-list thread尽管有主题,但仍涵盖了许多Racket中的功能更新方法(包括我对DSL的一些想法)。