您如何获得struct-copy来创建与原始类型相同的结构?

时间:2018-09-03 03:07:10

标签: struct racket

为说明起见,这是一个不变的结构和一个更新它的函数:

(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这样的函数,但是保留了原始结构的类型,这一事实使我怀疑我正在以错误的方式进行操作。是否有一些普通的方法可以实现相同的目的,而不会遇到返回与您开始时不同类型的结构的问题?

1 个答案:

答案 0 :(得分:2)

不幸的是,这是struct-copy的众所周知的局限性之一,其中大部分是由Sam Tobin-Hochstadt恰当地described实施的,因为它“将结构的某些位同质地粘贴在一起” (而不是复制结构的底层概念),并且是reason的一部分,即“ struct-copy是绝望的,如果不对结构的工作方式进行重大更改就无法解决。” Matthias Felleisen described将此视为“我们世界的致命弱点”。球拍社区肯定有改善这种状况的愿望,但是出于多种原因,这似乎令人生畏。我不知道有人在积极从事这项工作,有原则的解决方案看起来是一个悬而未决的问题。

在很多方面,结构对于球拍来说都是非常基本的。从概念上讲,Racket中的每个值都可以是某种结构类型的实例,尽管实际上,运行时系统对某些内置程序具有专门的表示形式。实际上,我认为正在进行的在Racket实现中用Chez Scheme替换C的工作可能会将结构用于旧式Racket VM中内置的某些内容。这是可能的,因为结构提供了强大的封装功能,尤其是通过inspectors。改进结构的工作方式本质上将影响整个Racket并涉及许多不同的考虑因素,尤其是在向后兼容方面。

以下是进一步了解该问题的一些提示:

    Sam的
  • This message概述了struct如何在保持向后兼容性的同时开始提供更多静态信息。
  • This GitHub issue,尤其是亚历克西斯(Alexis)的最后评论指出(a)不清楚要添加的正确静态信息是什么,(b)不会添加有关字段名称的静态信息。不足以解决子类型问题。
  • 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/genericracket/class)到创建可以更自然地使用的领域特定语言表达您的问题领域。 This mailing-list thread尽管有主题,但仍涵盖了许多Racket中的功能更新方法(包括我对DSL的一些想法)。