有没有办法在 Haskell 中创建"构造函数别名"?我的想法类似于类型别名,您可以在其中为类型指定不同的名称,但它仍然以各种方式表现为别名类型。
我的用例是一个系统,其中我有一个分配的时间作为我正在建模的某些对象的属性,所以UTCTime
.其中一些可能是"可变"时间,这意味着它可能尚未分配时间,或者它确实具有的时间是"可移动的"。所以Maybe UTCTime
.
但只有一些对象具有可变的时间。其他人则具有系统必须作为常数的固定时间;当前分配给特定时间的时间变量的处理方式与固定时间不同。现在建议Either UTCTime (Maybe UTCTime)
;它可以是固定时间,也可以是可能未分配的可变时间。
泛型类型似乎非常适合我尝试建模的内容,因此使用它们感觉很自然。但是,虽然Either UTCTime (Maybe UTCTime)
是什么很明显,但它的含义并不是特别明显,所以一些描述性的特殊情况名称会很好。
一个简单的type Timeslot = Either UTCTime (Maybe UTCTime)
肯定会清理我的类型签名,但这对构造函数没有任何作用。我可以使用类似 bound = Just
的东西来获取用于构造值的名称,但不能用于模式匹配的名称。
另一方面,我可以使用所需的任何名称定义自定义 ADT,但随后我将丢失 Either
和Maybe
类型的所有预定义功能。或者更确切地说,我会一直来回应用转换(我想这并不比使用 newtype
包装器的情况更糟,只是没有效率保证,但我怀疑这无论如何都会是一个瓶颈(。我想要使用通用Either
和Maybe
函数来操作我的Timeslot
值来理解代码,我需要知道标准构造函数映射到我想使用的任何内容的方式,并且转换函数将提供方便的编译器强制定义该映射。所以也许这毕竟是一个好方法。
我很确定我非常了解Haskell,可以说没有构造函数别名这样的东西,但我很好奇是否有一些我不知道的黑客,或者其他一些处理这种情况的好方法。
尽管您提到了缺点,但我强烈建议简单地为您的类型创建一个新的 ADT;
例如data TimeVariable = Constant UTCTime | Assigned UTCTime | Unassigned
我提出这些论点:
- 使用描述性构造函数将使你的代码(包括构造和模式匹配(更具可读性。比较
Unassigned
和Right Nothing
.现在添加六个月并进行相同的比较。 - 我怀疑随着应用程序的增长,您会发现此类型需要扩展。使用自定义 ADT 向现有构造函数添加另一个构造函数或另一个字段要容易得多,并且可以轻松识别需要更新以处理新类型的代码位置。
- 对于这种类型,可能不会有像标准库中那样多的明智操作来修改
Either
和Maybe
值 - 所以我敢打赌你不会复制你想象的那么多代码。尽管您可能会复制一些代码,但为您的函数提供描述性名称对于与为构造函数提供描述性名称相同的可读性和重构原因很有价值。
我 - 个人写了一些代码,其中我所有的金额都被
Either
,我的所有产品都被(,)
。太可怕了。我永远记不清一笔钱的哪一边意味着哪件事;在阅读旧代码时,我必须不断提醒自己每个值应该是什么概念类型(例如Right
没有告诉您您在这里使用Right
作为时间变量的一部分还是您懒得制作 ADT 的其他事物的一部分(;我不得不在精神上不断扩展类型别名;等。从我的痛苦中吸取教训。;-)
"模式同义词"可能会合并到 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 _ = ...