在(非常)现代的GHC中,我可以这样写:
{-# LANGUAGE TypeFamilies #-}
-- consider this part "library" code, changeable at will
data Container a = Container
data Element
class Foo a where foo :: a -> Int
instance Element ~ a => Foo (Container a) where foo _ = 0
-- consider this part "client" code; bonus points if it can remain exactly as is
main = print (foo Container)
突出点:
Container
是一个多态值(类型为Container a
),已正确地与Container Element
同构。Foo
的{{1}}的另一个实例。这是不我在以下讨论中保留的属性。这可以以更向后兼容的方式完成吗?我的第一次尝试看起来像这样:
Container
...这给出了一个错误:
{-# LANGUAGE FlexibleInstances #-}
data Container a = Container
data Element
class Foo a where foo :: a -> Int
instance Foo (Container Element) where foo _ = 0
main = print (foo Container)
我意识到这个错误可能是因为实例没有使用类型变量作为test.hs:8:15:
No instance for (Foo (Container a0))
arising from a use of `foo'
Possible fix: add an instance declaration for (Foo (Container a0))
In the first argument of `print', namely `(foo Container)'
In the expression: print (foo Container)
In an equation for `main': main = print (foo Container)
的参数,所以我也试过了:
Container
但这只是将问题推送到{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, UndecidableInstances #-}
data Container a = Container
data Element
class Foo a where foo :: a -> Int
instance Convertible a Element => Foo (Container a) where foo _ = 0
class Convertible a b where
-- convert is not necessary in this tiny example, but it would
-- be necessary in my not-so-tiny use case
convert :: Container a -> Container b
instance Convertible a a where
convert = id
main = print (foo Container)
类型类:
Convertible
为test.hs:14:19:
No instance for (Convertible a0 Element)
arising from a use of `foo'
Possible fix:
add an instance declaration for (Convertible a0 Element)
In the first argument of `print', namely `(foo Container)'
In the expression: print (foo Container)
In an equation for `main': main = print (foo Container)
而不是Convertible Element Element
编写实例会产生类似的错误。我最后的尝试是进一步专注:
Convertible a a
......它具有H98的显着优势,但仍然不太有效的显着缺点:
data Container a = Container
data Element
class Foo a where foo :: a -> Int
instance IsElement a => Foo (Container a) where foo _ = 0
class IsElement a where
convert :: a -> Element
instance IsElement Element where
convert = id
main = print (foo Container)
所以,问题是:是否有一些类似的实现实现了上面的属性1,2和3,但是不需要类型相等运算符?
编辑我认为排名2类型可能会有所帮助:
test.hs:10:19:
Ambiguous type variable `a0' in the constraint:
(IsElement a0) arising from a use of `foo'
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of `print', namely `(foo Container)'
In the expression: print (foo Container)
In an equation for `main': main = print (foo Container)
......但是,唉,仍然没有骰子:
{-# LANGUAGE FlexibleInstances, RankNTypes #-}
data Container a = Container
data Element
class Foo a where foo :: a -> Int
instance Foo (forall a. Container a) where foo _ = 0
main = print (foo Container)
答案 0 :(得分:2)
我不明白你在这里要做什么。特别是,当您只希望客户使用Container
时,为什么关心Container Element
是多态的?
那说,如何为类型类使用不同的类型?
data Container a = Container
data Element
class Foo a where foo :: a x -> Int
instance Foo Container where foo _ = 0
现在,将实例化的Container类型确实无关紧要。
如果这不起作用,我怀疑答案是“不,你不能做到你想要的。”虽然您可以导出container = Container :: Container Element
并让客户端代码使用该代码而不是Container
。
编辑:给定完整的上下文,并且也不可能使用rank-2类型,我可以合理地确定在给定问题约束的情况下没有解决方案。我能想到的最佳解决方法是创建一个新函数xcast :: XConfig a -> XConfig Layout
。这样您就可以编写instance Binding (XConfig a -> Foo)
。