5

有没有办法在 Haskell 中创建相当于创建“构造函数别名”的东西?我在想类似于类型别名,你可以给类型一个不同的名字,但它仍然在各个方面表现得像别名类型。

我的用例是一个系统,我有一个分配的时间作为我正在建模的某些对象的属性,所以UTCTime. 其中一些可能是“可变”时间,这意味着它可能尚未分配时间,或者它所拥有的时间是“可移动的”。所以Maybe UTCTime

但只有一些对象具有可变时间。其他人则有固定的时间,系统必须将其视为常数;当前分配给特定时间的时间变量的处理方式与固定时间不同。现在建议Either UTCTime (Maybe UTCTime); 它是固定时间或可能未分配的可变时间。

泛型类型似乎非常适合我想要建模的内容,因此使用它们感觉很自然。但是,虽然什么Either UTCTime (Maybe UTCTime) 显而易见的,但它的含义并不是特别明显,所以一些描述性的特殊情况名称会很好。

一个简单的type Timeslot = Either UTCTime (Maybe UTCTime)肯定会清理我的类型签名很多,但这对构造函数没有任何作用。我可以使用类似bound = Just获取名称来构造值,但不能用于模式匹配。

在另一端,我可以使用我想要的任何名称定义一个自定义 ADT,但是我失去了EitherandMaybe类型的所有预定义功能。或者更确切地说,我将一直来回应用转换(我认为这并不比使用newtype包装器的情况更糟,只是没有效率保证,但我怀疑这无论如何都会成为瓶颈)。而且我想理解使用泛型EitherMaybe函数来操作我的Timeslot值的代码我需要知道标准构造函数映射到我想要使用的任何东西的方式,并且转换函数将提供一个方便的编译器强制定义该映射. 所以也许这毕竟是一个好方法。

我很确定我非常了解 Haskell,可以说没有构造函数别名之类的东西,但我很好奇是否有一些我不知道的 hack,或者其他处理这种情况的好方法。

4

2 回答 2

18

尽管您提到了这些缺点,但我强烈建议您为您的类型创建一个新的 ADT;例如

data TimeVariable = Constant UTCTime | Assigned UTCTime | Unassigned

我提出以下论点:

  1. 拥有描述性构造函数将使您的代码——包括构造和模式匹配——明显更具可读性。比较UnassignedRight Nothing。现在加上六个月并做同样的比较。
  2. 我怀疑随着你的应用程序的增长,你会发现这种类型需要扩展。使用自定义 ADT 向现有构造函数添加另一个构造函数或另一个字段要容易得多,并且可以很容易地识别需要更新以处理新类型的代码位置。
  3. 这种类型的合理操作可能不会像标准库中用于修改EitherMaybe值的那样多——所以我敢打赌,你复制的代码不会像你想象的那样多。尽管你可能会重复一些代码,但给你的函数提供描述性名称是有价值的,因为它具有与给你的构造函数提供描述性名称相同的可读性和重构原因。
  4. 我亲自编写了一些代码,其中我的所有金额Either和我的所有产品都是(,)。那太差了。我永远记不得金额的哪一边代表什么。在阅读旧代码时,我必须不断提醒自己每个值应该是什么概念类型(例如Right,没有告诉你Right这里是用作时间变量的一部分还是其他一些你懒得做的东西的一部分为)制作ADT;我不得不不断地在精神上扩展类型别名;等等。从我的痛苦中学习。;-)
于 2013-09-29T00:07:58.527 回答
4

“模式同义词”可能会合并到 ghc:http://ghc.haskell.org/trac/ghc/ticket/5144。同时还有 -XViewPatterns,它可以让你编写如下内容:

type Timeslot = Either UTCTime (Maybe UTCTime)
fieldA = either Just (const Nothing)
fieldB = either (const Nothing) id


f (fieldA -> Just time) = ...
f (fieldB -> Just time) = ...
f _ = ...
于 2013-09-29T01:09:01.310 回答