Haskell类型与架构中的类型类

时间:2015-12-15 01:55:41

标签: haskell

假设我有一个应用程序,其核心数据是项目,文档集(“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应用程序)。

     

即使情况并非如此,在我看来应用程序也是如此   如果我可以创建一个新模块,定义我的文档更模块化   以及你可以用它做什么,现在支持bang,document。那   我在这里定义了我的分页文档,我的电子表格结束了   在那里,两个人根本不在乎彼此。

也许我可以使用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处理多态的方式?

2 个答案:

答案 0 :(得分:4)

那么,基于班级的提案甚至不起作用。类不是类型。如果[Doc]是一个类,则您无法Doc

这里通常的方法是确定你正在建模的是什么。

你想要一堆表现一致的东西,并且可以很容易地打包在一起吗?然后将该行为放入类型中。这通常是通过创建一个记录来完成的,该记录包含您想要的每种行为的函数。

另一方面,你有一堆需要非常不同处理的东西吗?在这种情况下,将数据放入一堆类型中,让类型检查器(和穷举检查器)一路指导您,确保您始终在正确的位置处理正确的事情。

我建议不要使用课程。类(大多数)只适用于可以编写类型多态代码的情况,这些代码在具体类型时是有意义的,但您不需要知道类型是什么。 (这有点夸大其词,但它足够接近事实,将其用作第一近似启发式算法。)

答案 1 :(得分:2)

  

假设我有一个核心数据为Projects,Document的应用程序   设置(“DocSets”)和文档(“Docs”)。文档不限于   任何特定的内容类型;它们可以是电子表格,图像,HTML,   等等,可以有其他文件没有的功能/行为。

听起来你不知道类型可以有多个构造函数(求和类型)。而不是你的Doc做:

data Doc = PagedTextDoc {docTitle :: Text, docContents :: ByteString}
         | SpreadsheetDoc {docTitle :: Text, docContents :: ByteString}
       ... etc
  

同样,我可能有多种DocSet,具体取决于   我需要的行为类型。也许这个DocSet以一种方式呈现文档   平面列表,也许是一个与每个文档相关联的状态,以及   根据状态有一些很酷的渲染技巧。

data DocSet = ListDocset Text [Doc] | KoolDocset [(Status, Doc)] | ...etc