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

标签 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 等)。有没有办法强制进行这种类型推断,而无需在调用站点中显式注释它?

最佳答案

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

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

现在,如果您想让它与 Text 类型一起使用并且不希望您的 用户要显式注释它,请提供 String 的两个实例 以及文本:

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 开销。

关于haskell - 对于这个例子,如何在 Haskell 中获得更好的多态类型推断?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27399978/

相关文章:

java - 为什么菱形运算符用于 Java 7 中的类型推断?

haskell - 查找局部函数的推断类型

parsing - "Sub-parsers"在管道-attoparsec

haskell - 每次都初始化计数器?

C++在多态子类中添加虚方法

java - 子类抛出异常的标准是什么

f# - 在这种情况下,为什么 F# 编译器不能推断类型?

haskell - forall 符号 : what does the period/dot mean?

haskell - 概括 mapAndUnzip

C++ 多态性 : going from base class to derived class