具有不同类型键的 Haskell 映射

标签 haskell types

我有一些类型

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/

相关文章:

Haskell - 类型包装器统一

haskell - Haskell 中的并发编程

在 GHCi 内的包模块中调试 IO

haskell - 在 Haskell 中实现一个高效的滑动窗口算法

haskell - 欧拉项目 2 : Haskell implementation confusion

Symfony Forms - 如何更改 CollectionTypes 项目标签

angular2 在构造函数中使用参数扩展服务

ruby-on-rails - Rails STI : How to change mapping between class name & value of the 'type' column

haskell - 为什么我的 Haskell 函数参数必须是 Bool 类型?

c++ - C++ 中 float 的 Setprecision()?