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.
上一篇: 如何使用算法W键入检查递归定义?