【发布时间】:2015-12-15 01:55:40
【问题描述】:
假设我有一个应用程序,其核心数据是项目、文档集(“DocSets”)和文档(“Docs”)。文档不限于任何特定的内容类型;它们可以是电子表格、图像、HTML 等,并且可以具有其他文档没有的功能/行为。同样,根据我需要的行为类型,我可能有多种 DocSet。也许这个 DocSet 将文档显示在一个平面列表中,也许将一个状态与每个文档相关联,并且有一些基于状态的很酷的渲染技巧。
如果我不使用类型类,代码可能如下所示:
data Project = Project {
projName :: Text,
projDocSets :: [DocSet]
}
data DocSet = DocSet {
dsName :: Text,
dsDocs :: [Doc]
}
data Doc = Doc {
docTitle :: Text,
docType :: Text,
docContents :: ByteString
}
我看到的问题是,虽然它允许存在多种文档(通过 docType 字段),但它本质上使用手动类型检查,这感觉不对(在我的脑海中)。我可以为 PagedTextDoc、ContinuousTextDoc、SpreadsheetDoc、ImageDoc 等提供数据构造函数。这对我来说似乎模块化很差。
编辑:我的“模块性差”评论依赖于没有很好地传达的知识。每个 Doc 都有一些共同的行为 ((反)序列化,被分组为一个 DocSet,一个标题,渲染, 其他随着应用程序的发展),以及一些独特的行为 (以易于编辑的格式进行内部表示,节省增量 编辑,部分呈现为 HTML 假设应用程序是一个 Web 应用程序)。
即使不是这样,在我看来,该应用程序也会是 如果我可以创建一个新模块,则更模块化,定义我的文档 以及您可以用它做什么,并且现在支持文档。那 方式,我在这里定义我的分页文档,我的电子表格在 在那里,两个人根本不关心对方。
也许我可以为 Docs 使用类型类?
data DocSet = DocSet {
dsName :: Text,
dsDocs :: [Doc]
}
class Doc d where
docTitle :: d -> Text
docType :: d -> Text
docContents :: d -> ByteString
dsDocs 的声明现在不进行类型检查;列表仅适用于一种特定的具体类型,而不是类型类的任何成员。 DocSet 肯定需要能够存储/引用多种文档。
我尝试进行一些搜索,但坦率地说,我的 Google 技能在这里完全失败了。我是否正确考虑了数据结构?将所有 (Proj, DocSet, Doc) 都作为单个数据构造函数的方法真的是处理这个问题的最佳方法,还是我错过了 Haskell 处理多态性的方式?
【问题讨论】:
-
第一种方法有什么问题?将
docType :: Text更改为docType :: DocumentType,这似乎非常明智。以哪种方式枚举您的文档类型的模块化较差? -
此外,如果您将类型类视为对“某物”建模,那么
class C x where f0 :: x -> T0; f1 :: x -> T1; .. fn :: x -> Tn形式的任何类型类都只是对具有字段{ f0 :: T0, .. , fn :: Tn }的记录进行建模。所以你的类公式化并不比你的记录类型公式更强大(正如你所看到的,实际上更难使用)。 -
编辑以试图澄清,但我可能做得不好。如果此应用程序将成为查看器,您的建议将非常有用。我可能需要稍后添加编辑,不知道这个时间表是什么。
标签: haskell