Haskell Typeclass для кортежей

Я играл со стилистами и делал это:

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

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

Затем я попытался добавить реализацию для (,) и понял, что могу сделать:

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

Я уверен, что это работает, потому что Secondable должен иметь вид (* → *), где ((,) a) имеет этот тип, однако я не знаю, как реализовать Initialable for ((,) * a ) где * - связанная переменная. В моей интерпретации я пытаюсь сделать эквивалент:

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

Есть ли способ сделать это в Haskell? Предпочтительно без расширений?

Спасибо!

Ответы

Ответ 1

Версия с худшими параметрическими гарантиями может быть выполнена с помощью MPTCS и Fundeps или с 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

...

но в конечном итоге вам нужно будет использовать некоторые расширения.

Ответ 2

Вы можете использовать семейства типов, подобные этому (другой подход к тому, что написал Эдвард):

{-# 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

Ответ 3

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

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