0
votes

I try to understand how data type families can be used to hide away a constructor. The trivial example given is a pair with operations to convert from and to ordinary pairs etc.). An instance for bifunctor does not compile; the error message is

src/TypeFamilyTest.hs:66:21: The first argument of Bifunctor should have kind * -> * -> *, but Pairs a b has kind ghc-prim-0.4.0.0:GHC.Prim.Constraint

In the instance declaration for Bifunctor (Pairs a b)

Trying Bifunctor Pair where ... I get another error message listing the same GHC.Prim.Constraint. What are the correct arguments for the instance and how will the context be passed?

class  Pairs a b where
    data Vec2 a b  

    mkPair :: (a,b) -> Vec2 a b   -- (FirstF a, SecondF a) -> a
    splitPair :: Vec2 a b -> (a,b)
    fstP ::  Vec2 a b -> a
    sndP ::  Vec2 a b -> b
    fstP = fst . splitPair
    sndP = snd . splitPair

instance ( ) => Bifunctor (Pairs a b) where
     bimap opv oph vh = mkPair  (opv . fstP $ vh, oph . sndP $ vh)
1
Data families are not about hiding constructors. Their constructors can be visible or hidden in all the same ways normal data types are. Data families are about non-parametric data types -- types which inspect their type arguments before deciding what their constructors look like.Daniel Wagner
A type class is not a class in the object-oriented sense. It does not encapsulate data and the operation that work on it.chepner
The closest OOP notion of a Haskell class is a Java-like interface, and even this correspondence is loose.chi
You can define a type newtype Vec2' a b = Vec2' (Vec2 a b) and you can make instances of typeclasses for this type to your hearts content. However, this type is not a Bifunctor. The type of bimap would be (Pairs a b, Pairs a' b') => (a -> a') -> (b -> b') -> Vec2' a b -> Vec2' a' b'user2407038
thank you for the clarification. I do not understand why you introduce a newtype. what is the difference between Vec2 and Vec2'? both have two parameters? what is the benefit of the additional wrapper?user855443

1 Answers

2
votes

The type error tells you everything. Pair is not the name of a datatype. It is the name of a class. Pair a b :: Constraint so Pair :: * -> * -> Constraint. Bifunctor can only be instantiated by datatypes of kind * -> * -> *.

I'm guessing you may have meant something like this:

newtype Pair a b = Vec2 { splitPair :: (a, b) }

fstP :: Pair a b -> a
fstP = fst . splitPair

sndP :: Pair a b -> b
sndP = snd . splitPair

instance Bifunctor Pair where
    bimap f g (Vec2 (x, y)) = Vec2 (f x, g y)

I don't understand why you originally made Vec2 an associated type. I suspect this may be an XY problem - what are you really trying to achieve?