haskell:制作Num的超类

时间:2012-03-26 11:04:40

标签: haskell typeclass superclass decidable

我想创建一个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)

2 个答案:

答案 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的实例,那就是编译时错误”。它不是很有用。除非您同时启用NumOverlappingInstances,否则您无法为不属于IncoherentInstances的类型添加更多实例。而那些的扩展可怕,只有当你知道自己在做什么时才应该使用它们。

答案 1 :(得分:3)

有一个proposal允许声明超类。 AFAIK尚未实现,但由于GHC是开源的,如果你愿意,可以改变它;)