Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Higher kinded types as type variables in Haskell

I have a class:

import Linear

class Coordinate c where
    rotate :: Num a => Quaternion a -> c a -> c a
    translate :: Num a => V3 a -> c a -> c a

, for which I have defined the instances

instance Coordinate V3 where
    rotate _ = id
    translate p = (p+)

instance Coordinate Quaternion where
    rotate o = (o*)
    translate _ = id

Now I want to define an instance for a pair of members of the class.

instance (Coordinate a, Coordinate b) => Coordinate (a, b) where
    rotate o (a, b) = (rotate o a, rotate o b)
    translate p (a, b) = (translate p a, translate p b)

The problem is that this does not work, since the compiler expects an argument for a and b. However adding a type-constraint like

instance (Coordinate a, Coordinate b, Num c) => Coordinate (a c, b c) where
    move p (a, b) = (move p a, move p b)
    translate p (a, b) = (translate p a, translate p b)

It does not work either, since this results in an expression with the kind * rather than * -> *. I can see how both of the above are incorrect, but I am unsure of how to solve this. I suppose there should be some form of constraint that keeps the Num types for both aand b the same, but I don't know what that would look like syntactically.

like image 316
notBob Avatar asked Dec 23 '19 02:12

notBob


People also ask

Why are there high Kinded types?

Higher-kinded types are useful when we want to create a container that can hold any type of items; we don't need a different type for each specific content type.

What languages support higher Kinded types?

Haskell has good support for higher kinded types. Every type constructor such as they [] can be used as a "first class type". This is specifically relevant to typeclasses such as the Functor typeclass. Each of those instances are implementations of the Functor class for a particular higher kinded type.

Is Monad a higher Kinded type?

The most-used example of higher-kinded type polymorphism in Haskell is the Monad interface.

Does rust have higher Kinded types?

Rust does not have higher-kinded-types. For example, functor (and thus monad) cannot be written in Rust.


1 Answers

You cannot make an instance of this Coordinate class for the built-in pair type. You need to change one of them.

  • The Coordinate class can be changed to take a normal Type as argument:

    {-# LANGUAGE FlexibleContexts, TypeFamilies #-}
    
    import Data.Kind (Type)
    
    class Num (Component c) => Coordinate c where
        type Component c :: Type -- every Coordinate type has a Component type
        rotate :: Quaternion (Component c) -> c -> c
        translate :: V3 (Component c) -> c -> c
    

    E.g the V3 instance will now look like

    instance Num a => Coordinate (V3 a) where
        type Component (V3 a) = a
        rotate _ = id
        translate = (+)
    

    And the pair instance will use an equality constraint, which is the thing you were looking for

    instance (Coordinate a, Coordinate b, Component a ~ Component b) => Coordinate (a, b) where
        type Component (a, b) = Component a -- or = Component b
        rotate p (l, r) = (rotate p l, rotate p r)
        translate p (l, r) = (translate p l, translate p r)
    
  • Instead of pairs, use Product:

    import Data.Functor.Product
    
    instance (Coordinate a, Coordinate b) => Coordinate (Product a b) where
        rotate p (Pair l r) = Pair (rotate p l) (rotate p r)
        translate p (Pair l r) = Pair (translate p l) (translate p r)
    
like image 157
HTNW Avatar answered Sep 21 '22 16:09

HTNW