体系结构中的Haskell类型与类型类

体系结构中的Haskell类型与类型类,haskell,Haskell,假设我有一个应用程序,其核心数据是项目、文档集(“docset”)和文档(“Docs”)。文档不限于任何特定的内容类型;它们可以是电子表格、图像、HTML等,并且可以具有其他文档所没有的功能/行为。类似地,根据需要的行为类型,我可能有多种类型的docset。也许这个文档集以一个平面列表的形式呈现文档,也许每个文档都有一个状态,并且有一些基于状态的很酷的呈现技巧 如果我没有使用TypeClass,代码可能如下所示: data Project = Project { projName :: Te

假设我有一个应用程序,其核心数据是项目、文档集(“docset”)和文档(“Docs”)。文档不限于任何特定的内容类型;它们可以是电子表格、图像、HTML等,并且可以具有其他文档所没有的功能/行为。类似地,根据需要的行为类型,我可能有多种类型的docset。也许这个文档集以一个平面列表的形式呈现文档,也许每个文档都有一个状态,并且有一些基于状态的很酷的呈现技巧

如果我没有使用TypeClass,代码可能如下所示:

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等提供数据构造函数,这对我来说似乎是糟糕的模块化

编辑:我的“模块性差”评论依赖于没有很好沟通的知识。每个文档都有一些常见的行为 ((反)序列化,分为文档集、标题、呈现、, 其他的(随着应用程序的发展),以及一些独特的行为 (易于编辑格式的内部表示,节省增量 编辑,部分呈现为HTML(假设应用程序是web应用程序)

即使情况并非如此,在我看来,该应用程序也会如此 更模块化如果我可以创建一个新模块,定义我的文档 您可以用它做什么,砰的一声,文档现在被支持了。那个 顺便说一下,我在这里定义我的分页文档,在这里定义我的电子表格 在那里,两个人根本不关心对方

也许我可以为文档使用typeclass

data DocSet = DocSet {
  dsName :: Text,
  dsDocs :: [Doc]
}

class Doc d where
  docTitle :: d -> Text
  docType :: d -> Text
  docContents :: d -> ByteString
dsDocs的声明现在不会进行类型检查;与typeclass的任何成员相比,仅列出一种特定具体类型的工作。DocSet肯定需要能够存储/引用多种文档


我试过做一些搜索,但坦率地说,我的谷歌技能在这里完全失败了。我对数据结构的思考是否正确?将所有(Proj、DocSet、Doc)作为单个数据构造函数的方法真的是处理这一问题的最佳方法吗?还是我缺少Haskell处理多态性的方法?

好吧,基于类的建议根本不起作用。类不是类型。如果
Doc
是一个类,则不能有
[Doc]

通常的方法是确定您正在建模的是什么

你想要一堆行为一致、易于打包的东西吗?然后将该行为放入类型中。这通常是通过创建一个记录来完成的,该记录为您想要的每种行为保存一个函数

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


我根本不建议使用类来实现这一点。类(大部分)只适用于当存在具体类型时可以编写有意义的类型多态代码,但不需要知道类型是什么的情况。(这有点夸张,但它非常接近事实,可以将其用作一次近似启发。)

好吧,基于类的建议根本不起作用。类不是类型。如果
Doc
是一个类,则不能有
[Doc]

通常的方法是确定您正在建模的是什么

你想要一堆行为一致、易于打包的东西吗?然后将该行为放入类型中。这通常是通过创建一个记录来完成的,该记录为您想要的每种行为保存一个函数

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

我根本不建议使用类来实现这一点。类(大部分)只适用于当存在具体类型时可以编写有意义的类型多态代码,但不需要知道类型是什么的情况。(这有点夸张,但它足够接近事实,可以将其用作一次近似启发。)

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

听起来好像你不知道类型可以有多个构造函数(和类型)。代替您的
文档
执行以下操作:

data Doc = PagedTextDoc {docTitle :: Text, docContents :: ByteString}
         | SpreadsheetDoc {docTitle :: Text, docContents :: ByteString}
       ... etc
类似地,我可能有多种文档集,具体取决于 我需要的行为类型。也许这个文档集以一种 平面列表,可能会将状态与每个文档关联,并且 有一些很酷的基于状态的渲染技巧

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

听起来好像你不知道类型可以有多个构造函数(和类型)。代替您的
文档
执行以下操作:

data Doc = PagedTextDoc {docTitle :: Text, docContents :: ByteString}
         | SpreadsheetDoc {docTitle :: Text, docContents :: ByteString}
       ... etc
类似地,我可能有多种文档集,具体取决于 我需要的行为类型。也许这个文档集以一种 平面列表,可能会将状态与每个文档关联,并且 有一些很酷的基于状态的渲染技巧。