По существу, все моноидальные элементы, используемые в методах моноидального функтора, относятся к целевой категории.Таким образом, он может быть формализован † :
class (Category s, Category t) => Functor s t f where
map :: s a b -> t (f a) (f b)
class Functor s t f => Monoidal s t f where
pureUnit :: t () (f ())
fzip :: t (f a,f b) (f (a,b))
s
-морфизмов, только если вы рассмотрите законы моноидального функтора, которые примерно говорят, что моноидальная структура s
должен быть отображен в эту моноидальную структуру t
с помощью функтора.
Возможно, более проницательным является включение fmap
в методы класса, поэтому ясно, что "func -" - частьФунктор делает:
class Functor s t f => Monoidal s t f where
...
puref :: s () y -> t () (f y)
puref f = map f . pureUnit
fzipWith :: s (a,b) c -> t (f a,f b) (f c)
fzipWith f = map f . fzip
С Monoidal
мы можем вернуть нашего старого доброго Hask - Applicative
таким образом:
pure :: Monoidal (->) (->) f => a -> f a
pure a = puref (const a) ()
(<*>) :: Monoidal (->) (->) f => f (a->b) -> f a -> f b
fs <*> xs = fzipWith (uncurry ($)) (fs, xs)
или
liftA2 :: Monoidal (->) (->) f => (a->b->c) -> f a -> f b -> f c
liftA2 f xs ys = fzipWith (uncurry f) (xs,ys)
Возможно, более интересным в этом контексте является другое направление, потому что оно показывает нам связь с монадами в обобщенном случае:
instance Applicative f => Monoidal (->) (->) f where
pureUnit = pure
fzip = \(xs,ys) -> liftA2 (,) xs ys
= \(xs,ys) -> join $ map (\x -> map (x,) ys) xs
То, что секции лямбды и кортежей недоступны вобщая категория, однако они могут быть переведены в декартовы закрытые категории .
† Я использую (,)
в качестве продукта вобе моноидальные категории, с единичным элементом ()
.В более общем случае вы можете написать data I_s
и data I_t
и type family (⊗) x y
и type family (∙) x y
для продуктов и соответствующих им элементов идентификации.