【问题标题】:Haskell map with keys from different types具有不同类型键的 Haskell 映射
【发布时间】:2012-09-10 18:27:53
【问题描述】:

我有一些类型

data Foo = Foo
data Bar = Bar 
data Baz = Baz

我想将它们用作 Map 的键。这可能吗?如果可以,怎么做?

下面的附加上下文:

我有一个构建虚拟机的应用程序。我已将工作分为几个阶段。目前我有这种类型

data CurrentPhase = PHASEONE
                  | PHASETWO
                  | PHASETHREE (deriving Eq,Ord)

到目前为止一切顺利,没有我上面提到的问题。但是,我创建了一个类型类来描述特定于阶段的操作

class PhaseOps phase where
  preValidate :: JobID -> phase -> Handler (Status)
  doPreProc :: JobID -> phase -> Handler (Status)
  updateConfig :: JobID -> phase -> Handler ()
  postValidate :: JobID -> phase -> Handler (Status)

为了使其工作,我必须创建一组新的单例数据类型以用于PhaseOps 实例。

data PhaseOne = PhaseOne

..等等

现在我有了这些单例类型和CurrentPhase。我想摆脱CurrentPhase(我将它用于以CurrentPhase 为键的地图),并使用我的单例数据类型。

【问题讨论】:

  • data FooBarBaz = Foo | Bar | Baz有问题吗? (具体来说,为什么这不起作用?)
  • 在单个映射中存储不同类型的键存在问题,我的意思是你将如何比较不同类型的两个值?您能做的最好的事情是为每种类型创建一个 Map 联合,并使用类型类(或类型族)围绕它编写自己的包装器。
  • 我开始认为 Map 是错误的数据结构。
  • @MichaelLitchard:好吧,如果您只是告诉我们您要解决什么问题,我们可以告诉您是否是这样。不要为了完成一个步骤而寻求帮助,而是为了达到一个目标而寻求帮助。有时,您试图为实现目标而采取的步骤只是错误的和误导性的。 (有时不是,但为什么要碰巧呢?)
  • 我注意到PhaseOps 看起来很像一个想要成为函数记录的类。

标签: haskell types


【解决方案1】:

直接的解决方案是使用Either Foo (Either Bar Baz) 类型的键。当您添加可能的类型时,这会很快变得冗长,并且无论如何有点难看,因此使用特殊用途的等价物通常更有意义,例如:

data FooBarBaz = FooVal Foo | BarVal Bar | BazVal Baz

这类似于将它们直接组合成一种类型,但在组合类型中牺牲了更多的冗长性,以便仍然能够在其他地方使用单独的类型。这是一种比较常见的模式;例如,我经常在表示语法树的类型中看到它,其中“顶级声明”类型可能采用这种形式,每种声明都是自己独立的类型。

根据您的问题的性质,可能还有其他更好的方法,但以上是我能想到的唯一好的通用解决方案——如果您不喜欢这样做,您您需要更清楚地说明为什么,并详细说明您需要这些类型来完成什么。


编辑以回应澄清:

正如我在问题的 cmets 中提到的,PhaseOps 看起来很像一个想要成为函数记录的类。此外,如果您有这样一个类,想要一种方法来处理多个实例类型,就好像它们是单一类型一样,这强烈表明是时候退后一步重新考虑您的设计了。

继续这样的设计几乎总是会导致要么与Typeable 混在一起,正如 Thomas M. DuBuisson 在 cmets 中提到的那样,要么与存在类型混在一起(这是当今众所周知的反模式) .确实偶尔需要这些方法,但最好避免使用,除非您可以非常清楚地解释(即使只是对自己)为什么需要它们。否则,他们制造的问题远远多于解决的问题。

顺便说一句,如果您想保留单独类型的一些好处,我会考虑使用您的单例类型进行幻像类型标记和/或隐藏PhaseOps 记录的构造函数,并使用带有CurrentPhase 参数。

【讨论】:

  • @MichaelLitchard:编辑了答案以匹配评论。 :]
猜你喜欢
  • 2015-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多