Подтвердить что ты не робот

Можно ли сделать тип экземпляром класса, если его параметры типа находятся в неправильном порядке?

Рассмотрим следующий тип:

data SomeType m a = SomeType (m Integer) [a]

Мы можем легко сделать этот тип экземпляром Functor со следующим кодом:

instance Functor (SomeType m) where
  fmap f (SomeType m lst) = SomeType m (map f lst)

Однако, если вместо этого были заменены параметры типа SomeType:

data SomeType2 a m = SomeType2 (m Integer) [a]

Тогда указанное выше определение экземпляра не работает.

Есть ли способ сделать SomeType2 экземпляр Functor? Если нет, есть ли какие-либо дополнения и дополнения к haskell/ghc, которые позволили бы это сделать?

4b9b3361

Ответ 1

Предвзятый я, но я думаю, что это отличная возможность использовать Control.Newtype, маленький кусок набора, который просто "cabal install newtype" прочь.

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

 newtype Flip f x y = Flip (f y x)

и добавьте его в класс Newtype, тем самым

 instance Newtype (Flip f x y) (f y x) where
   pack = Flip
   unpack (Flip z) = z

Класс Newtype представляет собой просто сопоставление типов newtypes с их неприкрашенными эквивалентами, предоставляя удобный набор, например. op Flip является инверсией Flip: вам не нужно помнить, как вы его назвали.

Для рассматриваемой проблемы теперь мы можем делать такие вещи:

 data Bif x y = BNil | BCons x y (Bif x y) deriving Show

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

instance Functor (Bif x) where
  fmap f BNil = BNil
  fmap f (BCons x y b) = BCons x (f y) (fmap f b)

... и один раз для первого:

instance Functor (Flip Bif y) where
  fmap f (Flip BNil) = Flip BNil
  fmap f (Flip (BCons x y b)) = Flip (BCons (f x) y (under Flip (fmap f) b))

где under p f - опрятный способ сказать op p . f . p.

Я тебе не лгу: давайте попробуем.

someBif :: Bif Int Char
someBif = BCons 1 'a' (BCons 2 'b' (BCons 3 'c' BNil))

а затем получим

*Flip> fmap succ someBif
BCons 1 'b' (BCons 2 'c' (BCons 3 'd' BNil))
*Flip> under Flip (fmap succ) someBif
BCons 2 'a' (BCons 3 'b' (BCons 4 'c' BNil))

В этих обстоятельствах действительно существует много способов, чтобы одно и то же можно было увидеть как Functor, поэтому правильно, что мы должны сделать некоторый шум, чтобы сказать, к какому способу мы имеем в виду. Но шум не так уж и много, если вы систематически об этом.

Ответ 2

Это невозможно, и я не думаю, что это будет в ближайшее время.

Важным является порядок параметров типа. Последнее значение - это то, которое вы собираетесь "содержать" для использования с Functor и т.д.

Я попытался заставить это работать, указав синоним типа, который перевернул параметры типа вокруг, а затем использовал расширение TypeSynonymInstances, но он не смог работать.

Ответ 3

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

Ответ 4

Тупой ответ, который вы уже знали, это: перевернуть ваши параметры!

Для GHC для поддержки такого рода вещей без какой-либо дополнительной упаковки вам понадобится что-то вроде lambdas типа уровня, которые, вероятно, в ближайшее время не будут добавлены. (Мне бы хотелось, чтобы в этом не было доказано)

instance Functor (\a -> SomeType2 a m) where
  -- fmap :: (a -> b) -> SomeType2 a m -> SomeType2 b m
  fmap f (SomeType2 lst m) = SomeType (map f lst) m

Поскольку у нас уже есть TypeSynonymInstances, мы могли бы надеяться на PartialAppliedTypeSynonymInstances когда-то чуть раньше, чем никогда.

type SomeType3 m a = SomeType2 a m

instance Functor (SomeType m) where
  -- fmap :: (a -> b) -> SomeType3 m a -> SomeType3 m b
  -- or, synonymously:
  -- fmap :: (a -> b) -> SomeType2 a m -> SomeType2 a m
  fmap f (SomeType2 lst m) = SomeType (map f lst) m