我想编写一个可以在数字(例如1)和字符串(例如"a")上调用的函数。在我的应用程序中尽可能地简化“用户代码”很重要。
我的代码的最小示例如下所示
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
type StrInt = Either String Int
class Lift a where
toStrInt :: a -> StrInt
instance Lift String where
toStrInt= Left
instance Lift Int where
toStrInt= Right
declare:: StrInt ->String
declare (Left a) = "String: " ++ a
declare (Right n) = "Number: " ++ (show n)
declare' :: Lift a => a -> String
declare' a = declare (toStrInt a)
myDecA = declare' "a"
myDec1 = declare' 1
Run Code Online (Sandbox Code Playgroud)
编译这给出了错误
Ambiguous type variable ‘a0’ arising from a use of ‘declare'’
prevents the constraint ‘(Lift a0)’ from being solved.
Run Code Online (Sandbox Code Playgroud)
我理解这个问题,我知道我可以用以下任何一项替换最后一行:
myDec1 = declare' (1::Int)myDec1 = declare (Right 1)但这违背了我想要达到的目的。是否有一种巧妙的方法来设置相同的想法,以便明确 1 是一个 Int?
此外,在我的应用程序中(比上面的最小示例更复杂)该declare函数仅适用于Ints。所以我不能一概而论Num a。
使用 Haskell 是不可能的。这样做的原因是虽然1 看起来像Int,但实际上是Num a => a。Haskell 没有办法知道这Int是唯一a满足的(Num a, Lift a) => a,所以需要明确地告诉它。例如,如果我在另一个模块中创建以下实例:
instance Num String where
...
Run Code Online (Sandbox Code Playgroud)
然后declare' 1变得模棱两可,并可能合理地导致"String:..."或"Int:..."。Haskell 在编译时无法知道我不会这样做,所以我们遇到了问题。