Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
具有不同类型键的Haskell映射_Haskell_Types - Fatal编程技术网

具有不同类型键的Haskell映射

具有不同类型键的Haskell映射,haskell,types,Haskell,Types,我有一些类型 data Foo = Foo data Bar = Bar data Baz = Baz 我想把它们用作地图的键。这可能吗?如果可能,如何实现 附加上下文如下: 我有一个构建虚拟机的应用程序。我已将工作分为几个阶段。目前我有这种类型 data CurrentPhase = PHASEONE | PHASETWO | PHASETHREE (deriving Eq,Ord) 到目前为止还不错,没有我上面提到

我有一些类型

data Foo = Foo
data Bar = Bar 
data Baz = Baz
我想把它们用作地图的键。这可能吗?如果可能,如何实现

附加上下文如下:

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

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
作为键的映射),并使用我的单例数据类型。

简单的解决方案是使用
或Foo(或Bar Baz)
类型的键。当您添加可能的类型时,这会很快变得冗长,而且有点难看,因此使用特殊用途的等效项通常更有意义,例如:

data FooBarBaz = FooVal Foo | BarVal Bar | BazVal Baz
这类似于将它们直接组合到一个类型中,但是在组合的类型中,为了能够在其他地方仍然使用单独的类型,需要在更详细的程度上进行权衡。这是一种比较常见的模式;例如,我经常在表示语法树的类型中看到它,其中“顶级声明”类型可能采用这种形式,每种声明都是它自己的独立类型

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


根据澄清进行编辑:

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

继续这样的设计几乎总是导致要么像Thomas M.DuBuisson在评论中提到的那样使用可键入的,要么使用存在类型(这是当今众所周知的反模式)。的确,这种方法偶尔需要,但最好避免,除非你能非常清楚地解释(即使只是对自己)为什么需要它们。否则,它们产生的问题远远多于它们解决的问题


顺便说一句,如果您想保留单独类型的一些优点,我会考虑使用单体类型进行幻像类型标记和/或隐藏构造函数用于<代码> PrimeOP>/代码>记录,并使用一个智能构造函数,使用一个<代码> CurrentPhase < /C> >参数。< /P>是否存在一个问题:<代码>数据FoBoBaBZ= Foo.bar BAZ < /代码>?(具体来说,这为什么不起作用?)在一个映射中存储不同类型的键有一个问题,我的意思是如何比较不同类型的两个值?你能做的最好的事情就是为每种类型创建一个映射的并集,并使用类型类(或类型族)围绕它编写你自己的包装。我开始认为映射是错误的数据结构。@MichaelLitchard:好吧,如果你简单地告诉我们你试图解决的问题,我们可以告诉你是否是这样。不要为了完成一个步骤而寻求帮助,而是为了达到一个目标而寻求帮助。有时,你试图采取的步骤只是错误的和误导性的。(有时不是,但为什么要冒险呢?)我注意到,
PhaseOps
看起来非常像一个想要成为函数记录的类。@MichaelLitchard:编辑答案以匹配注释。:]