Представляемый функтор, изоморфный (Bool → a)

Я подумал, что попробую интригующий Representable-functors пакет, чтобы определить экземпляр Monad и Comonad для заданного функтора на data Pair a = Pair a a, который представляется Bool; как упоминалось в ответе мой предыдущий вопрос о векторной монаде.

Первое, что я заметил, это то, что для того, чтобы сделать мой тип экземпляром Representable, я должен не только определять tabulate и index, но также гарантировать, что мой тип является экземпляром Indexable, Distributive, Keyed, Apply, Applicative и Functor. Хорошо, хорошо, index завершает определение Indexable, а функция <.> Apply может использовать <*> из Applicative; и не должно быть неожиданностью, что требуется экземпляр Functor. Тем не менее, я сомневаюсь в своих экземплярах для Keyed и Distributive.

data Pair a = Pair a a
  deriving (Show,Eq)

instance Functor Pair where
  fmap f (Pair x y) = Pair (f x) (f y)

type instance Key Pair = Bool

instance Keyed Pair where
  mapWithKey f (Pair x y) = Pair (f False x) (f False y)

instance Indexable Pair where
  index (Pair x _) False = x
  index (Pair _ y) True  = y

instance Applicative Pair where
  pure a = Pair a a
  Pair f g <*> Pair x y = Pair (f x) (g y)

instance Apply Pair where
  (<.>) = (<*>)

instance Distributive Pair where
  collect f x = Pair (getL . f <$> x) (getR . f <$> x)
    where getL (Pair x _) = x
          getR (Pair _ y) = y

instance Representable Pair where
  tabulate f = Pair (f False) (f True)

My mapWithKey определение берет из определения экземпляра [] для Keyed: хотя я не понимаю, почему 0 использовался там для каждой итерации. Аналогично я использовал False для каждого члена Pair.

Как я заключил, определяя экземпляры Monad и Comonad, я обнаружил, что Bool требует определения Semigroup для Extend и определения Monoid для Comonad. Я следую примеру Semigroup для Either, который изоморфен (||), и выберите False для mempty:

instance Monad Pair where
  return = pureRep
  (>>=)  = bindRep

instance Monoid Bool where
  mempty = False
  mappend = (||)

instance Semigroup Bool where
  (<>) = mappend

instance Extend Pair where
  extend = extendRep -- needs Bool Semigroup

instance Comonad Pair where
  extract = extractRep -- needs Bool Monoid

Итак, правильно ли я отвечал требованиям класса Representable и идиоматически?

Ответы

Ответ 1

Да, есть. Хотя ваш экземпляр для Keyed отключен.

instance Keyed Pair where
    mapWithKey f (Pair x y) = Pair (f False x) (f True y)

или даже проще

instance Keyed Pair where
    mapWithKey = mapWithKeyRep

и аналогично

instance Distributive Pair where
    distribute = distributeRep

Учитывая index и tabulate, вы можете использовать различные методы fooRep в модуле Representable для определения определений для всех других суперклассов.

Определения Extend и Comonad на самом деле не являются частью требований к Representable. Они включены, хотя, будучи представимыми, вы изоморфны функции, которая позволяет вам перерабатывать определение для "экспоненциального" Comonad (aka cowriter или Traced comonad), чтобы стать Comonad, а также, учитывая некоторый моноид в вашем представлении. Это не требуется, хотя, в основном потому, что я не могу сдерживать его, чтобы удержать данные типы.

Возможно, вы захотите отбросить Semigroup и Monoid для Bool, хотя и просто ручную реализацию Extend и extract. Это достаточно легко.

instance Extend Pair where
    extend f [email protected](Pair a b) = Pair (f p) (f (Pair b a))

instance Comonad Pair where
    extract (Pair a b) = a

Кроме того, этот тип предоставлен representable-tries, который включает в себя ряд других экземпляров.

и

import Control.Applicative
bool = [True, False]
f tt _tf _ft _ff True  True  = tt
f _tt tf _ft _ff True  False = tf
f _tt _tf ft _ff False True  = ft
f _tt _tf _ft ff False False = ff
associative f = and (assoc <$> bool <*> bool <*> bool) where 
    assoc a b c = f (f a b) c == f a (f b c)
semigroups = filter associative 
    [ f tt tf ft ff | tt <- bool, tf <- bool, ft <- bool, ff <- bool ]
unital (u, f) = all unit bool where 
    unit a = f u a == a && f a u == a
monoids = filter unital 
    [ (u, f) | u <- bool, f <- semigroups ]

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