如何使用不同键类型的IntMap?

时间:2011-08-01 17:09:32

标签: haskell types

我在一个使用两个IntMaps的文档中有一条记录:

data Doc = Doc { kernels :: IntMap Kernel, nodes :: IntMap Node }

但是我发现来自两个IntMaps的键具有不同的含义,并且我无法在两种不同类型中分离,并且在混合内核类型和节点类型时不会出错。我想要有从内核映射和节点映射检查密钥的函数,并且不允许混淆。 E.g:

someFunction :: Doc -> KernelKey -> NodeKey -> a
someFunction doc k1 k2 = .....

而不是当前:

someFunction :: Doc -> Int -> Int -> a
someFunction doc k1 k2 = .... -- warning check twice k1 and k2

它可以吗?或者我将从IntMap更改为Map

由于

2 个答案:

答案 0 :(得分:11)

您可以使用newtype围绕Int制作包装,以区分其含义。

newtype KernelKey = KernelKey Int
newtype NodeKey = NodeKey Int

someFunction :: Doc -> KernelKey -> NodeKey -> a
someFunction doc (KernelKey k1) (NodeKey k2) = ...

这样,您仍然可以在内部使用IntMap,但会公开更安全的类型界面,尤其是如果您还控制KernelKeyNodeKey值的创建方式,即您不要导出它们的构造函数,因此用户只能将它们作为其他函数的返回值。

请注意newtype包装器在运行时消失,因此这种额外的包装和解包不会以任何方式影响性能。

答案 1 :(得分:3)

您可以创建统一的密钥类型并为您的Doc类型包装IntMap API。它可能看起来像这样。

data DocValue = DocKernel Kernel
              | DocNode Node
data DocKey = KernelKey Int
            | NodeKey Int

docLookup :: DocKey -> Doc -> Maybe DocValue

该解决方案的优点在于您只需要每个所需的每个map API函数的一个副本。这是一个更接近你所拥有的代码的不同解决方案。

newtype NodeKey = NodeKey Int
newtype KernelKey = KernelKey Int
lookupDocNode :: NodeKey -> Doc -> Maybe Node
lookupDocKernel :: KernelKey -> Doc -> Maybe Kernel

您也可以在没有newtypes的情况下执行此解决方案。这两种解决方案都为您提供了类型安在第一个中,您必须使用类型指定所需的内容。在第二个中,您可以通过选择要调用的函数来指定它。

相关问题