可以用于一种简单的多态吗?

时间:2012-01-13 17:36:22

标签: haskell

我尝试编写一个简单的函数,它接受一个Either类型(可能由两个不同类型参数化)并且如果它变为Left则执行一个操作,如果它变为Right则执行另一个操作。以下代码,

someFunc :: (Show a, Show b) => Either a b -> IO ()
someFunc (Left x) = print $ "Left " ++ show x
someFunc (Right x) = print $ "Right " ++ show x

main = do
  someFunc (Left "Test1")
  someFunc (Right "Test2")

然而,这给了,

Ambiguous type variable `b0' in the constraint:
      (Show b0) arising from a use of `someFunc'
    Probable fix: add a type signature that fixes these type variable(s)
    In a stmt of a 'do' expression: someFunc (Left "Test1")

Ambiguous type variable `a0' in the constraint:
      (Show a0) arising from a use of `someFunc'
    Probable fix: add a type signature that fixes these type variable(s)
    In the expression: someFunc (Right "Test2")

如果我理解正确,当我使用Left x调用该函数时,它会抱怨,因为它不知道Right x变体的类型,反之亦然。但是,不使用此功能的分支。有更好的方法吗?

3 个答案:

答案 0 :(得分:5)

您可以通过明确指定其他类型来完成此工作:

main = do
  someFunc (Left "Test1" :: Either String ())
  someFunc (Right "Test2" :: Either () String)

但我同意x13n,这可能不是你做任何事情的最佳方式。请注意,someFunc在功能上与

相同
someFunc :: (Show a) => Bool -> a -> IO ()
someFunc False x = print $ "Left " ++ show x
someFunc True x = print $ "Right " ++ show x

因为您从Either的结构中获得的唯一信息是Left还是Right。此版本也不要求您在使用时指定占位符类型。

答案 1 :(得分:5)

这是一个很好的问题,因为它让我想到为什么 Haskell就是这样做的。

class PseudoArbitrary a where
  arb :: a

instance PseudoArbitrary Int where
  arb = 4

instance PseudoArbitrary Char where
  arb = 'd'

instance PseudoArbitrary Bool where
  arb = True

reallyDumbFunc :: (PseudoArbitrary a, PseudoArbitrary b) =>
                  Either a b -> Either a b
reallyDumbFunc (Left x) = Right arb
reallyDumbFunc (Right x) = Left arb

所以检查一下。我创建了一个类型类PseudoArbitrary,其中类型类的实例提供了它们类型的(伪)任意元素。现在我有reallyDumbFunc Either a b a,其中bPseudoArbitrary都有Left个实例,如果放Right in,我生成一个b,其中有一个(伪)任意值ghci> reallyDumbFunc (Left 'z') Ambiguous type variable blah blah blah ghci> reallyDumbFunc (Left 'z' :: Either Char Char) Right 'd' ghci> reallyDumbFunc (Left 'z' :: Either Char Int) Right 4 ,反之亦然。现在让我们来玩ghci:

reallyDumbFunc

哇!尽管我改变的只是输入的 type ,但它完全改变了输出的类型和值!这就是Haskell无法解决模糊性的原因:因为这需要以复杂的方式分析你的函数,以确保你没有做{{1}}之类的事情。

答案 2 :(得分:3)

嗯,这在很大程度上取决于你想要做什么,不是吗?正如您已经发现的,为了使用Left构造函数,您需要知道它构造的类型。完整类型需要ab的信息。

在Haskell中实现多态的更好方法是使用类型类。您可以轻松地提供"方法的不同实现"对于不同的实例。

可以找到面向对象和类型类概念的良好比较here