【问题标题】:Haskell module naming conventionsHaskell 模块命名约定
【发布时间】:2012-07-20 15:40:21
【问题描述】:

我应该如何为程序而不是库命名我的 Haskell 模块,并按层次结构组织它们?

我正在制作一个名为 Luminosity 的光线追踪器。首先我有这些模块:

Vector Colour Intersect Trace Render Parse Export

每个模块都很好,但我觉得这缺乏组织。

首先,我将每个模块都放在Luminosity 下,例如Vector 现在是Luminosity.Vector(我认为这是haskell 程序的标准?)。

然后我想:Vector和Color是独立的,可以复用,所以应该分开。但是它们太小了,不能变成图书馆。

他们应该去哪里?已经有(在hackage上)Data.Vector和Data.Colour,我应该把它们放在那里吗?或者这会导致混淆(即使我将它们与其他本地进口组合进口)?如果没有,应该是Luminosity.Data.Vector 还是Data.Luminosity.Vector?我很确定我已经看到两者都使用过,尽管我可能只是碰巧看到了一个使用非常规结构的项目。

我还有一个简单的 TGA 图像导出器 (Export),它可以独立于 Luminosity。看起来正确的位置应该是Codec.Image.TGA,但同样,Luminosity 应该在某个地方吗?如果是,在哪里?

如果Structure of a Haskell project 或其他 wiki 对此进行解释,那就太好了。

【问题讨论】:

  • 如果您想制作可重用的代码,请将其打包到库中。大小无关紧要。
  • 可见几何基元的可重用模块 - 具有代数类型,向量和颜色非常容易定义,以至于 Haskeller 想要定义自己的而不是依赖另一个库。然后他们可以控制他们的表现,而不必担心依赖问题(API 更改、作者失踪等)

标签: haskell module functional-programming naming-conventions code-organization


【解决方案1】:

除非你的程序真的很大,不要按层次组织模块。为什么不呢?因为尽管计算机擅长等级制度,但人却不擅长。人们擅长有意义的名字。如果您选择好的名称,您可以在一个平面名称空间中轻松处理 150 个模块。

我觉得 [一个扁平的命名空间] 缺乏组织性。

等级组织本身并不是目的。为了证明将模块分成层次结构的合理性,您需要一个原因。好的理由往往与信息隐藏或重用有关。当您引入信息隐藏时,您就完成了库设计的一半,而当您谈论重用时,您实际上是在构建一个库。将一个大程序变身为“小程序加库”是软件进化的一个好策略,但看起来你才刚刚开始,你的程序还不够大,无法以这种方式进化.

这些问题在很大程度上与您使用的编程语言无关。我建议阅读 David Parnas 的一些关于产品线和程序系列的工作,以及 Matthias Blume 的被低估的论文Hierarchical Modularity。这些作品将为您提供一些关于等级何时开始服务于目的的更具体的想法。

【讨论】:

  • 这是一个有趣的视角!我的程序中通常至少有某种形式的分层组织。 “真的很大”的数量级阈值是多少?
  • 我有点理解你的论点,但我不同意这与编程语言无关的想法。至少为了避免命名冲突,应该引入一个级别 (Luminosity.*)——不过我不确定你是否将其视为一个层次结构。我并没有真正询问层次结构的利弊,而是专门询问 Haskell 约定。或许这是单车,但 Haskell base 层次结构(以及 Hackage 上的包)似乎比 Java 或 Python 的约定大不相同,也没有那么简单。
  • 关于平面与层次结构的讨论,我为我的 8 模块程序创建层次结构的原因是:大约一半的模块与光线追踪无关。我可以在本地的文件浏览器中适当地组织它们,但在 GitHub 上它们都是按字母顺序排列的。我认为通过对相关模块进行分组,人们可以更轻松地了解所有内容。这似乎与您所争论的完全相反。
  • @ChrisTaylor:按照我的标准,我从来没有做过真正的大事。但是扁平结构对我来说在 10,000 到 50,000 行代码的项目中效果很好,可能有 80 到 150 个模块。也许 100,000 行真的很大?
  • @Mk12:这很快就会进入讨论,而不是问答,但我看到你的冲动好一点。许多项目都有一个“罪恶箱”,有用但不直接相关的东西会被扔进去。这是一种模糊通用的东西,但还不够大或不够好,无法变成图书馆。我通常打电话给我的罪箱Util。至于base 层次结构,它明确是library,而不是program,因此适用不同的规则。
【解决方案2】:

首先我把每个模块都放在Luminosity下

我认为这是一个很好的举措。它向正在阅读代码的任何人阐明,这些模块是专门为Luminosity 项目制作的。

如果您编写模块的目的是模拟或改进现有库,或者填补您认为缺少特定通用库的空白,那么在极少数情况下,请删除前缀并通用命名。有关这方面的示例,请参阅 pipes 包如何导出 Control.Monad.Trans.Free,因为无论出于何种原因,作者对 Free monad 的现有实现都不满意。

然后我想,Vector 和 Color 几乎是独立的,可以重复使用,所以应该分开。但是它们太小了,无法分离到一个库中(分别为 125 行和 42 行)。他们应该去哪里?

如果您不创建单独的库,则可能将它们留在Luminosity.Vector 和Luminosity.Colour。如果您确实创建了单独的库,请尝试向这些库的目标受众发送电子邮件,看看其他人认为这些库应该如何命名和分类。是否将它们拆分为单独的库完全取决于您以及您认为这些单独的库可能为其他人提供多少好处。

【讨论】:

  • 我接受了您的回答,因为我认为它对我的帮助最大且具体,但我结合了您、Norman 和 Stephen 的(对问题的评论)的建议。正如你所说,我会将所有内容都保留在Luminosity. 之下。我不会费心用我的小模块制作库或删除前缀,因为正如斯蒂芬所说,每个程序都可能想要自己的向量和颜色。我会保持一切平坦,而不是在Luminosity. 下引入层次结构,因为 Norman 给出的原因。
猜你喜欢
  • 2019-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-13
  • 2013-02-20
相关资源
最近更新 更多