不明确的中间结果
Ambiguous intermediate result
假设我有一个类型类、两个实例和一个定义如下的函数。
class C c where
newC :: String -> c
showC :: c -> String
data C1 = C1 String
instance C C1 where
newC string = C1 string
showC (C1 string) = string
data C2 = C2 String
instance C C2 where
newC string = C2 string
showC (C2 string) = string
topFn :: String -> String
topFn = showC . newC
加载时,GHC 产生 "Ambiguous type" 错误,
Ambiguous type variable ‘c0’ arising from a use of ‘showC’
prevents the constraint ‘(C c0)’ from being solved.
Probable fix: use a type annotation to specify what ‘c0’ should be.
These potential instances exist:
instance C C1 -- Defined at ambigType.hs:8:10
instance C C2 -- Defined at ambigType.hs:14:10
我知道中间值可能是 C1
或 C2
,如果没有进一步的信息,GHC 无法确定它应该是哪个。
编写两个版本的 topFn
解决问题。
topFn1 :: String -> String
topFn1 = showC . (newC :: String -> C1)
topFn2 :: String -> String
topFn2 = showC . (newC :: String -> C2)
但由于它们本质上是相同的功能,因此这似乎是一个丑陋的解决方案。有没有更好的方法?
谢谢。
是的,使用 TypeApplications
、AllowAmbiguousTypes
、ExplicitForall
和 ScopedTypeVariables
扩展名。然后,修改topFn
为
topFn :: forall a. C a => String -> String
topFn = showC . newC @a
然后,您可以使用显式类型应用程序调用 topFn
:topFn @C1 "calling the C1 variant"
和 topFn @C2 "calling the C2 variant"
。如果你愿意,你可以定义:
topFn1 = topFn @C1
topFn2 = topFn @C2
假设我有一个类型类、两个实例和一个定义如下的函数。
class C c where
newC :: String -> c
showC :: c -> String
data C1 = C1 String
instance C C1 where
newC string = C1 string
showC (C1 string) = string
data C2 = C2 String
instance C C2 where
newC string = C2 string
showC (C2 string) = string
topFn :: String -> String
topFn = showC . newC
加载时,GHC 产生 "Ambiguous type" 错误,
Ambiguous type variable ‘c0’ arising from a use of ‘showC’
prevents the constraint ‘(C c0)’ from being solved.
Probable fix: use a type annotation to specify what ‘c0’ should be.
These potential instances exist:
instance C C1 -- Defined at ambigType.hs:8:10
instance C C2 -- Defined at ambigType.hs:14:10
我知道中间值可能是 C1
或 C2
,如果没有进一步的信息,GHC 无法确定它应该是哪个。
编写两个版本的 topFn
解决问题。
topFn1 :: String -> String
topFn1 = showC . (newC :: String -> C1)
topFn2 :: String -> String
topFn2 = showC . (newC :: String -> C2)
但由于它们本质上是相同的功能,因此这似乎是一个丑陋的解决方案。有没有更好的方法?
谢谢。
是的,使用 TypeApplications
、AllowAmbiguousTypes
、ExplicitForall
和 ScopedTypeVariables
扩展名。然后,修改topFn
为
topFn :: forall a. C a => String -> String
topFn = showC . newC @a
然后,您可以使用显式类型应用程序调用 topFn
:topFn @C1 "calling the C1 variant"
和 topFn @C2 "calling the C2 variant"
。如果你愿意,你可以定义:
topFn1 = topFn @C1
topFn2 = topFn @C2