Haskell: class instance with class type parameters

Good afternoon. I am new to Haskell. It is not clear to me that you need to declare and instantiate some custom classes.

  • Haskell has a standard Integral class. According to the hack, Integral declares the required method quot :: a -> a -> a . So this means that every instance of this class must have an implementation of this method, right?

  • We can declare some function using Integral as an argument, for example:

 proba :: (Integral a) => a -> a -> a proba xy = x `quot` y 

So far so good

  1. Now let's declare our own Proba class:
 class Proba a where proba :: a -> a -> a 

I can implement an instance of Int or Integer (or another data type), for example:

 instance Proba Integer where proba xy = x `quot` y instance Proba Int where proba xy = x `quot` y 

But I dont want. I want one instance for each Integral. But when I try to do this, I get an error message:

 instance (Integral a) => Proba a where proba xy = x `quot` y Illegal instance declaration for `Proba 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 FlexibleInstances if you want to disable this.) In the instance declaration for `Proba a' 

Well, it seems like it is asking me for different type variables instead of classes. But why?! Why is this not enough to just have Integral here? Since quot declared for each Integral , this instance must be valid for each Integral , shoudn't it?

Maybe there is a way to achieve the same effect?

+6
source share
1 answer

As indicated in the error message, you can use FlexibleInstances (a fairly common and safe extension) to enable this behavior, but you will also need UndecidableInstances :

 {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE UndecidableInstances #-} class Proba a where proba :: a -> a -> a instance Integral a => Proba a where proba = quot 

The reason this is not enabled by default is because it specifically extends GHC and is not part of the Haskell98 specification. You will find that there are many language extensions that are very useful and safe to use, and often you want them to be included only in certain modules. Instead of just asking “why is this not the default”, also ask “when do I not want this to be the default?”.


Another way to implement this without extensions is to encode the type class directly as a data type:

 data Proba a = Proba { proba :: a -> a -> a } integralProba :: Integral a => Proba a integralProba = Proba quot 

Then you can pass it as

 foldProba :: Proba a -> a -> [a] -> a foldProba p = foldr (proba p) 

Then, if you have foldProba integralProba , then it automatically limits the type Integral a => a -> [a] -> a .

+5
source

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


All Articles