haskell:制作Num的超类 [英] haskell : making a superclass of Num

查看:139
本文介绍了haskell:制作Num的超类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个Num的超类,称为线性

 类Linear a其中
add :: a - > a - >

实例(Num a)=>线性a
add =(+)

我得到错误:

 '线性a'的非法实例声明
(所有实例类型都必须是形式(T a1 ... an)
其中a1 ... an是不同类型的变量*,
,每个类型变量在实例头中至多出现一次
如果要禁用它,请使用-XFlexibleInstances。)
在`Linear a'的实例声明中

据我所知, code> instance(Num a)=>线性的不正确。 (它编译如果我使用标志: -XFlexibleInstances -XUndecidableInstances



有没有办法实现这一点使用那些可怕的标志? (以及世界上对上述代码的不可判定性)?

更新:将多项式类型添加到线性。

  newtype多项式a =多项式(a,[a])导出Show  - 系数列表

实例(线性a )=>线性(多项式a)
其中
add(Polynomial(c1,l1))(多项式(c2,l2))
=多项式(add c1 c2,zipWith(add)l1 l2)

p1 =多项式(0,[3,4,5])
p2 =多项式(0,[])

main = putStrLn $ show((add p1 p2):: Polynomial Int)

添加多项式后,即使使用这些标志也不会编译并给出错误:

 由于使用'add'而产生的Linear(Polynomial Int)
的重叠实例
匹配实例:
实例Num a =>线性a - 定义于Algebra.hs:22:10-28
实例Linear a =>线性(多项式a)
- 定义于Algebra.hs:25:10-44
在`show'的第一个参数中,即
`((add p1 p2):: Polynomial在$($)'的第二个参数中,即
`show((add p1 p2):: Polynomial Int)'
在表达式中:putStrLn $ show((添加p1 p2):: Polynomial Int)


解决方案

报告不允许实例类型的实例...其中... ,所以避免 FlexibleInstances (这是不可怕的)将是使用新类型的包装,

  newtype LinearType a =线性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)其中
add = liftLin2(+)

Yuck。



需要 UndecidableInstances 扩展名,因为约束 Num a 不是小于实例头(它使用相同类型的变量的次数相同),所以编译器无法事先证明类型检查会终止。因此,你必须向编译器承诺,类型检查将终止它接受程序(它实际上不会与GHC循环,它具有控制类型检查器的递归深度的上下文栈,所以如果类型检查没有' t很快就会完成,它会通过上下文堆栈超出编译失败 - 您可以使用 -fcontext-stack = N )来设置大小。



这个扩展听起来比它更可怕。基本上它所做的只是告诉编译器相信我,类型检查将终止,因此编译器会在不知道它会完成的情况下启动。



但是,什么是你试图达到?你现在有什么,

  instance(Num a)=>线性的a在哪里
add =(+)

表示每种类型都是Linear ,并且如果您尝试在类型中使用add而不是Num的实例,那就是编译时错误。这不是很有用。除非您还启用 OverlappingInstances 并可能 IncoherentInstances 。这些扩展很可怕,只有在你知道自己在做什么时才应该使用它们。


I want to make a superclass of Num, called Linear

class Linear a where 
  add :: a -> a -> a

instance (Num a) => Linear a where
  add = (+)

I get the error :

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'

From what I understand, something about the line instance (Num a) => Linear a where is incorrect. (It compiles if I use the flags : -XFlexibleInstances -XUndecidableInstances)

Is there a way to achieve this without using those scary flags? (and what in the world is undecidable about the code above??)

UPDATE : Added Polynomial type to Linear.

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)

After adding polynomial, it doesn't compile with even those flags and give the error:

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)

解决方案

The language report doesn't allow instances of the form instance Class a where..., so the only way to avoid FlexibleInstances (which is not scary in the least) would be to use a newtype wrapper,

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 (+)

Yuck.

The UndecidableInstances extension is needed because the constraint Num a is not smaller than the instance head (it uses the same type variables the same number of times), so the compiler can't prove in advance that type checking will terminate. Thus you have to promise to the compiler that type checking will terminate for it to accept the programme (it won't actually loop with GHC, that has a context stack that controls recursion-depth of the type checker, so if type checking doesn't finish soon enough, it will fail the compilation with "context stack exceeded" - you can set the size with -fcontext-stack=N).

This extension sounds much scarier than it is. Basically all it does is tell the compiler "Trust me, type checking will terminate" so the compiler will start without knowing for sure that it will finish.

But, what are you trying to achieve? What you currently have,

instance (Num a) => Linear a where
  add = (+)

says "every type is an instance of Linear, and if you try to use add at a type not an instance of Num, that is a compile-time error". It's not very useful. You cannot add further instances for types not belonging to Num, unless you enable also OverlappingInstances and possibly IncoherentInstances. And those extensions are scary, they should be used scarcely and only when you know what you're doing.

这篇关于haskell:制作Num的超类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆