Представляемый функтор, изоморфный (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 полугрупп.