Are type synonyms possible with class restrictions?

Feel free to change the name, I'm just not experienced enough to find out what is really happening.

So, I wrote a program based on this and wrote this (as in the original)

type Row a = [a] type Matrix a = [Row a] 

Nothing special. However, I found that I am writing a couple of functions with this type:

 Eq a => Row a -> ... 

So, I thought that perhaps I could write this restriction in defining a type synonym, because in my opinion it should not be much more complicated, right? If the compiler can work with this in functions, it should work as a type synonym. There are no partial applications or anything else or some kind of deception (before my eyes).

So, I tried this:

 type Row a = Eq a => [a] 

This does not work, and the compiler suggested enabling RankNTypes . The option did compilation, but the functions still require me to leave Eq a => in my type declarations. Aside, if I also tried to have a type synonym, for example type Matrix a = [Row a] , as before, this leads to an error.

So my question (s):

  • Is it possible to have a type synonym with a typeclass type restriction in its definition?

    • If not, why?
  • Is the goal behind this issue achievable in any other way?

+5
source share
2 answers

Constraints on a type variable cannot be part of any Haskell type signature.

This may seem like a slightly ridiculous statement: "what (==) :: Eq a => a -> a -> a then?"

The answer is that a really does not exist, in much the same way x does not exist in the definition of fx = x * log x . You, of course, have used the x symbol enough to define this function, but in reality it was only the local tool used in lambda abstraction. There is absolutely no way to access this symbol from the outside, in fact, the compiler does not even need to generate anything that matches x into machine code - it could just be optimized.

Indeed, any polymorphic signature can basically be read as a lambda expression that takes a type variable; various writing styles:

 (==) :: forall a . Eq a => a -> a -> a (==) :: βˆ€ a . Eq a => a -> a -> a (==) :: Ξ›a. {Eq a} -> a -> a -> a 

This is called System F.

Note that there is no β€œrestriction” in this signature, but an additional argument: the Eq -class dictionary.

+3
source

Usually you want to avoid restrictions on synonyms of your type, if really necessary. Take the Data.Set API from containers , for example.

Many operations in Data.Set require that the elements of a set be Ord instances, because Set implemented internally as a binary tree. member or insert both require Ord

 member :: Ord a => a -> Set a -> Bool insert :: Ord a => a -> Set a -> Set a 

However, the definition of Set does not mention Ord at all.

This is because some Set operations do not require an Ord instance, such as size or null .

 size :: Set a -> Int null :: Set a -> Bool 

If a class type constraint was part of the Set definition, these functions would have to include the constraint, although this was not necessary.

So, there may be limitations in type synonyms using RankNTypes , but this is usually not recommended. It’s better to write a constraint for the functions they need.

+1
source

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


All Articles