我有一个术语类型,其本质是:
data Term a = Term a Bool
deriving Show
这Bool
是一种辅助功能,只是偶尔需要。如果不需要,我希望用户可以跳过它。这意味着以下内容应该有效:
main :: IO ()
main = print v
where v = "a"
=: Term "b" True
=: []
在哪里:
class Join a b where
(=:) :: a -> [b] -> [b]
infixr 1 =:
instance Join a (Term a) where
x =: y = Term x False : y
instance Join (Term a) (Term a) where
x =: y = x : y
唉,GHC 抱怨道:
a.hs:15:8-12: error: [GHC-39999]
• Ambiguous type variable ‘b0’ arising from a use of ‘print’
prevents the constraint ‘(Show b0)’ from being solved.
Relevant bindings include v :: [b0] (bound at a.hs:17:8)
但如果我main
这样写:
main :: IO ()
main = print v
where v :: [Term String]
v = "a"
=: Term "b" True
=: []
那么一切都好了。(请注意,唯一的区别是我给出了v
类型签名。)
我很好奇是否存在一种现代 GHC 技巧(类型系列、Injective-Type-families、Closed-type-families、GADT 等,或者一些神奇的标志),可以使类型签名变得不必要,并让 GHC 无需任何帮助即可推断出类型本身。
以下是完整程序:
data Term a = Term a Bool
deriving Show
class Join a b where
(=:) :: a -> [b] -> [b]
infixr 1 =:
instance Join a (Term a) where
x =: y = Term x False : y
instance Join (Term a) (Term a) where
x =: y = x : y
main :: IO ()
main = print v
where v :: [Term String] -- Want to avoid this signature and let GHC deduce it.
v = "a"
=: Term "b" True
=: []
问题是,我是否可以应用一些 GHC 功能或技巧,这样v
就不需要类型签名了。我也很乐意更改Join
类或添加新参数/依赖项等,只要的局部定义v
可以按原样编写而无需类型签名。
如果有充分的正当理由说明我所要求的是不合理的,我也希望得到一个解释,说明为什么这是不可能的。在我看来,GHC 有足够的类型信息来推断类型本身,但我怀疑某种“开放世界”假设正在发挥作用,并且所有“封闭类型系列”之类的技巧都不会奏效;如果确实如此。要清楚的是,我很高兴该类Join
永远不会在任何其他类型上实例化。