我有一个名为Foo
的类,它拥有一个函数gen :: Int -> [Foo]
。例如,我可以通过这种方式创建Foo
的实例:
data FooTest = FooTest Int
instance Foo FooTest where
gen n = replicate n (FooTest 0)
现在,让我们假设我有另一个名为Bar
的类,它定义了一个函数bar :: Bar -> IO ()
。 Foo
的每个实例都必须是Bar
的实例,但是 Bar
实现对于每个实例都是完全相同的。这是一个例子:
class Foo f where
gen :: Int -> [f]
class Bar b where
bar :: b -> IO ()
instance Bar Foo where -- obviously that doesn’t work
bar _ = putStrLn "bar through any Foo instance"
instance (Foo f) => Bar f where -- this needs the FlexibleInstance GHC extension first, then it still throws shit saying that the constraint is not smaller that I don’t shit
bar _ = putStrLn "bar through any Foo instance"
这里的问题是我找不到任何方法使一个类成为另一个的实例,提到第一个类的任何实例将共享相同的实现以实现其他类的实例化。
有什么想法吗?
提前致谢。
答案 0 :(得分:4)
使用两个扩展程序FlexibleInstances
和UndecidableInstances
,您可以使用上一个实例准确完成所需内容。
就像名称所暗示的那样,第二个扩展允许您编写不终止的实例。这可能会在编译时导致无限循环;但是,实现在某个递归深度任意上限,所以你不应该有无限的编译时间。
我根本不知道有什么方法可以做到这一点。但是,除非您可能希望将来使用其他编译器,否则使用扩展本身并不是很糟糕。
另外,随机样式注释:如果您只有一个约束,则括号是可选的。所以你可以把它写成:
instance Foo f => Bar f where ...
这不是很重要,但我认为第二个版本看起来更好。