首页 > 解决方案 > 可以在 Strings 和 Int 上调用的函数。模糊类型变量问题

问题描述

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

编译它会给出错误

 Ambiguous type variable ‘a0’ arising from a use of ‘declare'’
      prevents the constraint ‘(Lift a0)’ from being solved.

我了解这个问题,并且我知道我可以将最后一行替换为以下任何内容:

但这违背了我想要达到的目的。有没有一种巧妙的方法来设置相同的想法,从而清楚地表明 1 是一个 Int?

此外,在我的应用程序中(比上面的最小示例更复杂)该declare函数仅适用于Ints。所以我不能一概而论Num a

标签: haskell

解决方案


使用 Haskell 是不可能的。这样做的原因是,虽然1 看起来Int,但实际上是Num a => a。Haskell 没有办法知道这Int是唯一a满足的(Num a, Lift a) => a,所以需要明确地告诉它。例如,如果我在另一个模块中创建以下实例:

instance Num String where
    ...

然后declare' 1变得模棱两可,并且可以合理地导致"String:..."or "Int:..."。Haskell 在编译时无法知道我不会这样做,所以我们遇到了问题。


推荐阅读