Я подумал, что попробую интригующий 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
и идиоматически?