我想创建一个Num的超类,叫做Linear
class Linear a where
add :: a -> a -> a
instance (Num a) => Linear a where
add = (+)
我收到错误:
Illegal instance declaration for `Linear a'
(All instance types must be of the form (T a1 ... an)
where a1 ... an are *distinct type variables*,
and each type variable appears at most once in the instance head.
Use -XFlexibleInstances if you want to disable this.)
In the instance declaration for `Linear a'
根据我的理解,关于行instance (Num a) => Linear a where
的某些内容是不正确的。 (如果我使用标志,它会编译:{{1}})
有没有办法在不使用那些可怕的旗帜的情况下实现这一目标? (以及世界上关于上述代码的不可判断的内容??)
更新:将多项式类型添加到线性。
-XFlexibleInstances -XUndecidableInstances
添加多项式后,它甚至不会使用这些标志进行编译并给出错误:
newtype Polynomial a = Polynomial (a,[a]) deriving Show-- list of coeffients
instance (Linear a) => Linear (Polynomial a)
where
add (Polynomial (c1, l1)) (Polynomial (c2, l2))
= Polynomial (add c1 c2, zipWith (add) l1 l2)
p1 = Polynomial (0, [3,4,5])
p2 = Polynomial (0, [])
main = putStrLn $ show ((add p1 p2):: Polynomial Int)
答案 0 :(得分:10)
语言报告不允许使用instance Class a where...
形式的实例,因此避免FlexibleInstances
(至少不可怕)的唯一方法是使用newtype包装器,
newtype LinearType a = Linear a
liftLin2 :: (a -> b -> c) -> LinearType a -> LinearType b -> LinearType c
liftLin2 op (Linear x) (Linear y) = Linear (op x y)
instance Num a => Linear (LinearType a) where
add = liftLin2 (+)
呸。
需要UndecidableInstances
扩展名,因为约束Num a
不小于实例头(它使用相同次数的相同类型变量),因此编译器无法提前证明类型检查将终止。因此,您必须向编译器承诺,类型检查将终止它以接受程序(它实际上不会与GHC循环,它具有控制类型检查器的递归深度的上下文堆栈,因此如果类型检查没有'很快完成,它将无法通过“超出上下文堆栈”进行编译 - 您可以使用-fcontext-stack=N
设置大小。
这个扩展听起来比它更可怕。基本上它所做的只是告诉编译器“信任我,类型检查将终止”,因此编译器将在不确定它将完成的情况下启动。
但是,你想要实现什么目标?你现在有什么,
instance (Num a) => Linear a where
add = (+)
说“每个类型都是Linear的一个实例,如果你尝试在类型中使用add而不是Num的实例,那就是编译时错误”。它不是很有用。除非您同时启用Num
和OverlappingInstances
,否则您无法为不属于IncoherentInstances
的类型添加更多实例。而那些的扩展可怕,只有当你知道自己在做什么时才应该使用它们。
答案 1 :(得分:3)
有一个proposal允许声明超类。 AFAIK尚未实现,但由于GHC是开源的,如果你愿意,可以改变它;)