Haskell: Creating a Num Superclass

I want to make a superclass from Num called Linear

class Linear a where add :: a -> a -> a instance (Num a) => Linear a where add = (+) 

I get an error message:

 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 wrong. (It compiles if I use the flags: -XFlexibleInstances -XUndecidableInstances )

Is there any way to achieve this without using these scary flags? (and what is undecidable in the world regarding the code above?)

UPDATE : polynomial type added 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 a polynomial, it does not compile even with these flags and does not report an 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) 
+6
source share
2 answers

The language report does not allow instances of the form instance Class a where... , so the only way to avoid FlexibleInstances (which is not at all scary) is to use the newtype shell,

 newtype LinearType a = Linear a liftLin2 :: (a -> b -> c) -> LinearType a -> LinearType b -> LinearType c liftLin2 op (Linear x) (Linear y) = Linear (op xy) instance Num a => Linear (LinearType a) where add = liftLin2 (+) 

Ugh.

The extension UndecidableInstances necessary because the restriction of Num a not less than the head of the instance (it uses the same type of variables the same number of times), so the compiler cannot prove in advance that type checking will stop. Therefore, you must promise the compiler that the type check is completed so that it can accept the program (in fact, it will not work with GHC, which has a context stack that controls the depth of the type check recursion, so if type checking does not work, t finish soon enough, this will cause compilation to fail with "exceeding the context stack" - you can set the size with -fcontext-stack=N ).

This extension sounds a lot worse than it is. Basically, all he does is tell the compiler "Believe me, type checking will end", so the compiler will start, not knowing for sure what it will finish.

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

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

says that "each type is an instance of Linear, and if you try to use add in a type, and not in a Num instance, this is a compile-time error." This is not very helpful. You cannot add additional instances for non- Num types unless you also include OverlappingInstances and possibly IncoherentInstances . And these extensions are scary, they need to be used hardly and only when you know what you are doing.

+10
source

There is a proposal to allow the declaration of superclasses. AFAIK it is not yet implemented, but since GHC is open source, you can change it if you want;)

+3
source

Source: https://habr.com/ru/post/911660/


All Articles