我尝试编写一个简单的函数,它接受一个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
变体的类型,反之亦然。但是,不使用此功能的分支。有更好的方法吗?
答案 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
,其中b
和PseudoArbitrary
都有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
构造函数,您需要知道它构造的类型。完整类型需要a
和b
的信息。
在Haskell中实现多态的更好方法是使用类型类。您可以轻松地提供"方法的不同实现"对于不同的实例。
可以找到面向对象和类型类概念的良好比较here。