可以在 Strings 和 Int 上调用的函数。歧义类型变量问题

San*_*lar 3 haskell

我想编写一个可以在数字(例如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

And*_*Ray 5

使用 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 在编译时无法知道我不会这样做,所以我们遇到了问题。