在这个例子中,如何在Haskell中获得更好的多态类型推断?

时间:2014-12-10 11:33:31

标签: haskell polymorphism type-inference

我有以下数据类型:

data PValue = IV Int | BV Bool | SV String
            deriving (Show, Eq)

我想编写一个从Int,Bool或String生成PValue的函数,如:

> loadVal 3
IV 3

> loadVal True
BV Bool

> loadVal "Ha"
SV "Ha"

由于loadVal的参数是多态的,我试图创建一个类:

class PValues v where
  loadVal :: v -> PValue

instance PValues Int where
  loadVal v = IV v

instance PValues Bool where
  loadVal v = BV v

instance PValues String where
  loadVal s = SV s

除Int:

外,这似乎有效
> loadVal "Abc"
SV "Abc"
> loadVal False
BV False
> loadVal 3

<interactive>:8:1:
    No instance for (PValues v0) arising from a use of `loadVal'
    The type variable `v0' is ambiguous
    Note: there are several potential instances:
      instance PValues String -- Defined at Types.hs:22:10
      instance PValues Bool -- Defined at Types.hs:19:10
      instance PValues Int -- Defined at Types.hs:16:10
    In the expression: loadVal 3
    In an equation for `it': it = loadVal 3

<interactive>:8:9:
    No instance for (Num v0) arising from the literal `3'
    The type variable `v0' is ambiguous
    Note: there are several potential instances:
      instance Num Double -- Defined in `GHC.Float'
      instance Num Float -- Defined in `GHC.Float'
      instance Integral a => Num (GHC.Real.Ratio a)
        -- Defined in `GHC.Real'
      ...plus 8 others
    In the first argument of `loadVal', namely `3'
    In the expression: loadVal 3
    In an equation for `it': it = loadVal 3

我理解这是因为3本身具有不明确的类型(可能是IntFloat等等。有没有办法强制这种类型的推理而不在调用站点中明确地注释它?

1 个答案:

答案 0 :(得分:4)

在此扩展@ AndrewC的评论。要使loadVal 3工作,请执行 实例化时的类型转换:

instance PValues Integer where
  loadVal v = IV (fromInteger v)

现在,如果你想让它与Text类型一起使用而不想要你的 用户明确注释它,为String提供两个实例 以及Text

data PValue = IV Int | BV Bool | SV Text
            deriving (Show, Eq)

instance PValues String where
  loadVal s = SV (pack s)

instance PValues Text where
  loadVal s = SV s

对于编译器能够推断出您的输入的位置 Text数据类型,不必经过pack开销。