Kar*_*ran 6 haskell typeclass superclass decidable
我想创建一个名为Linear的Num超类
class Linear a where
add :: a -> a -> a
instance (Num a) => Linear a where
add = (+)
Run Code Online (Sandbox Code Playgroud)
我收到错误:
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'
Run Code Online (Sandbox Code Playgroud)
根据我的理解,关于这条线的事情instance (Num a) => Linear a where是不正确的.(它编译如果使用标志:-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)
Run Code Online (Sandbox Code Playgroud)
添加多项式后,它甚至不会使用这些标志进行编译并给出错误:
Overlapping instances for Linear (Polynomial Int)
arising from a use of `add'
Matching instances:
instance Num a => Linear a -- Defined at Algebra.hs:22:10-28
instance Linear a => Linear (Polynomial a)
-- Defined at Algebra.hs:25:10-44
In the first argument of `show', namely
`((add p1 p2) :: Polynomial Int)'
In the second argument of `($)', namely
`show ((add p1 p2) :: Polynomial Int)'
In the expression: putStrLn $ show ((add p1 p2) :: Polynomial Int)
Run Code Online (Sandbox Code Playgroud)
Dan*_*her 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 (+)
Run Code Online (Sandbox Code Playgroud)
呸.
在UndecidableInstances需要扩展,因为限制Num a不超过实例头(它使用相同类型的变量相同的次数)较小,因此编译器不能提前证明类型检查将终止.因此,您必须向编译器承诺,类型检查将终止它以接受程序(它实际上不会与GHC循环,它具有控制类型检查器的递归深度的上下文堆栈,因此如果类型检查没有'很快完成,它将失败编译"超出上下文堆栈" - 您可以设置大小-fcontext-stack=N).
这个扩展听起来比它更可怕.基本上它所做的只是告诉编译器"信任我,类型检查将终止",因此编译器将在不确定它将完成的情况下启动.
但是,你想要实现什么目标?你现在有什么,
instance (Num a) => Linear a where
add = (+)
Run Code Online (Sandbox Code Playgroud)
说"每个类型都是Linear的一个实例,如果你尝试在类型中使用add而不是Num的实例,那就是编译时错误".它不是很有用.您不能添加其他情况下的类型不属于Num,除非你也能OverlappingInstances和可能IncoherentInstances.这些扩展是可怕的,它们应该几乎不用,只有当你知道自己在做什么时.