How to get better Polymorphic Type Inference in Haskell for this example?

I have the following data type:

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

I want to write a function that generates PValue from an Int, a Bool or a String like:

> loadVal 3
IV 3

> loadVal True
BV Bool

> loadVal "Ha"
SV "Ha"

Since the argument to loadVal is polymorphic, I tried to create a class:

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

This appears to work, except for 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

I understand that this is because 3 by itself is of ambiguous type (could be Int , Float , etc). Is there a way to force this type inference without explicitly annotating it in the call site?


Expanding @AndrewC's comment here. For making loadVal 3 work, do the type conversion while instantiating:

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

Now, if you want to make it work with Text type and don't want your user to explicitly annotate it, give both the instances for String as well as 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

For places, where the compiler is able to infer that your input is Text data type, it will not have to go through the pack overhead.

链接地址: http://www.djcxy.com/p/7458.html

上一篇: 如何使用算法W键入检查递归定义?

下一篇: 如何在这个例子中得到更好的Haskell中的多态类型推断?