我有一些类型
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
实例。
数据 PhaseOne = PhaseOne
..等等
现在我有了这些单例类型和CurrentPhase
。我想摆脱 CurrentPhase
(我用于以 CurrentPhase
为键的 map ),并使用我的单例数据类型。
最佳答案
最简单的解决方案是使用 Either Foo (Either Bar Baz)
类型的键。当您添加可能的类型时,这很快就会变得冗长,并且无论如何都有点难看,因此使用特殊用途的等效项通常更有意义,例如:
data FooBarBaz = FooVal Foo | BarVal Bar | BazVal Baz
这类似于直接将它们组合成一种类型,但牺牲了组合类型中的更多冗长,以便在其他地方仍然可以使用各个类型。这是一种比较常见的模式;例如,我经常在表示语法树的类型中看到它,其中“顶级声明”类型可能采用这种形式,每种声明都是其自己的单独类型。
根据您问题的性质,可能还有其他更好的方法,但以上是我能想到的唯一好的通用解决方案 - 如果您不喜欢这样做,那么您'您需要更清楚地指定原因,并详细说明您需要这些类型来完成什么任务。
<小时/>编辑以回应澄清:
正如我在该问题的评论中提到的,PhaseOps
看起来很像一个想要成为函数记录的类。此外,如果您有这样一个类,那么想要一种像处理单一类型一样处理多个实例类型的方法,就非常强烈地表明,是时候退后一步,重新思考您的设计了。
继续这样的设计几乎总是会导致要么搞乱 Typeable
,正如 Thomas M. DuBuisson 在评论中提到的那样,要么搞乱存在类型(这是众所周知的反) -这些天的模式)。确实,这些方法偶尔是需要的,但最好避免,除非您可以非常清楚地解释(即使只是对自己)为什么需要它们。否则,他们制造的问题远多于解决的问题。
顺便说一句,如果您想保留单独类型的一些好处,我会考虑使用单例类型进行幻像类型标记和/或隐藏 PhaseOps
记录的构造函数并使用接受 CurrentPhase
参数的智能构造函数。
关于具有不同类型键的 Haskell 映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12357432/