15
votes

I was playing around with typeclasses and made this:

class Firstable f where
  fst :: f a -> a

class Secondable f where
  snd :: f a -> a

I then tried to add an implementation for (,) and realized that I could do:

instance Secondable ((,) a) where
  snd (x,y) = y

I'm pretty sure this works because Secondable should have kind (* -> *) where ((,) a) has that type, however, I don't know how to implement Firstable for ((,) * a) where * is the bound variable, In my interpretation I am trying to do the equivalent of:

instance Firstable (flip (,) a) where ...

Is there a way to do this in Haskell? Preferably without extensions?

3
AFAIK, no: you'd need TypeSynonymInstances, but type synonyms cannot be partially evaluated. But are you aware of the alternative with MultiParamTypeClasses? That's perhaps a bit ugly, but it works. - leftaroundabout
You might be interested in how the tuple package handles this: hackage.haskell.org/package/tuple - John L

3 Answers

10
votes

You can use type families like so (A different take on what Edward wrote):

{-# LANGUAGE TypeFamilies #-}

class Firstable a where
  type First a :: *
  fst :: a -> First a

class Secondable a where
  type Second a :: *
  snd :: a -> Second a

instance Firstable (a,b) where
  type First (a, b) = a
  fst (x, _) = x

instance Secondable (a,b) where
  type Second (a, b) = b
  snd (_, y) = y
1
votes
class Firstable f where
    fst :: f a b -> a

class Secondable f where
    snd :: f a b -> b
1
votes

A version with worse parametricity guarantees can be had with MPTCS and Fundeps or with TypeFamilies.

type family Fst p
type instance Fst (a,b) = a
type instance Fst (a,b,c) = a

...

class First p where
   fst :: p -> Fst p

instance Fst (a,b) where
   fst (a,_) = a

instance Fst (a,b,c) where
   fst (a,_,_) = a

...

but ultimately, you'll need to use some extensions.