多态模式匹配导致类型不明确 [英] Polymorphic pattern matching results in ambiguous type
问题描述
(受的启发,无法在具有约束的多态元组上进行匹配,并基于我自己的答案随后的评论.)
(Inspired by cannot match on polymorphic tuples with constraints, and based on a subsequent comment on my own answer.)
请考虑以下最小示例:
test :: (Show a, Show b) => (a -> String, b -> String)
test = (show,show)
(resX, resY) = test
这将导致以下错误:
• Ambiguous type variable ‘a0’ arising from a use of ‘test’
prevents the constraint ‘(Show a0)’ from being solved.
Relevant bindings include
resX :: a0 -> String (bound at so.hs:25:2)
Probable fix: use a type annotation to specify what ‘a0’ should be.
These potential instances exist:
instance Show Ordering -- Defined in ‘GHC.Show’
instance Show Integer -- Defined in ‘GHC.Show’
instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
...plus 22 others
...plus 17 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In the expression: test
In a pattern binding: (resX, resY) = test
|
25 | (resX, resY) = test
| ^^^^
这很有意义:模式匹配不会以任何方式限制a
或b
,因此它们是模棱两可的.但是如何摆脱这个错误呢?几乎所有通过添加类型签名来解决此问题的尝试都会产生另一个错误.例如:
This makes sense: that pattern match doesn’t constrain a
or b
in any way, so they’re ambiguous. But how do I get rid of this error? Just about every attempt to solve this by adding type signature(s) gives another error. For instance:
-- attempt 1
test :: (Show a, Show b) => (a -> String, b -> String)
test = (show,show)
resX :: Show a => a -> String
resY :: Show b => b -> String
(resX, resY) = test
-- attempt 2
test :: (Show a, Show b) => (a -> String, b -> String)
test = (show,show)
(resX, resY) = test :: (Show a, Show b) => (a -> String, b -> String)
所以:如何摆脱歧义性错误?为什么上述尝试失败了?
So: how can I get rid of the ambiguity error? And why do the above attempts fail?
推荐答案
这很有意义:模式匹配不会以任何方式限制a或b,因此它们是模棱两可的.但是如何摆脱这个错误?
This makes sense: that pattern match doesn’t constrain a or b in any way, so they’re ambiguous. But how do I get rid of this error?
提供类型签名在这里无济于事. test
的类型是(Show a, Show b) => (a -> String, b -> String)
.基本上,您要做的就是写:
Giving type signatures will not help here. The type for test
is (Show a, Show b) => (a -> String, b -> String)
. Basically what you do is write:
resX :: Show a => a -> String
resX = fst test
但是问题是,Haskell应该从test
的签名中为b
填写什么?您可能会说这没关系,在这里确实没关系.但是,例如,如果您通过类型类定义了test
. a
和b
类型可以共同确定第一个项目的实现方式.例如:
The question is however, what should Haskell fill in for b
from the signature of test
? You might say that this does not matter, and here it indeed does not matter. But if you defined test
through a typeclass for example. The a
and b
type could determine together what the implementation for the first item would be. For example:
{-# LANGUAGE MultiParamTypeClasses #-}
class (Show a, Show b) => SomeTest a b where
test :: (a -> String, b -> String)
instance SomeTest Bool Bool where
test = (const "foo", const "bar")
instance SomeTest Bool Int where
test = (const "qux", const "bar")
这里的第二个类型参数确定test
的第一项的实现,因此我们不能仅仅忽略它.
here the second type parameter determines the implementation of the first item of test
, and hence we can not just omit that.
例如,您可以使用TypeApplications
扩展名,为其他类型参数(此处为Bool
)提供类型:
You can for example use the TypeApplications
extension, to provide a type for the other type parameter (here Bool
):
{-# LANGUAGE TypeApplications -#}
test :: (Show a, Show b) => (a -> String, b -> String)
test = (show, show)
resX :: Show a => a -> String
resX = fst (test @_ @Bool)
resY :: Show a => a -> String
resY = snd (test @Bool)
这篇关于多态模式匹配导致类型不明确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!