Je pense que vous y réfléchissez légèrement. Un bifoncteur est juste comme un foncteur à deux paramètres. L'idée de Gibbons et Oliveira n'est qu'une application des bifoncteurs, tout comme le zoo standard des systèmes de récursion n'est qu'une application des foncteurs.
class Bifunctor f where
bimap :: (a -> c) -> (b -> d) -> f a b -> f c d
Bifunctor
s ont une sorte de * -> * -> *
et les deux paramètres peuvent être mis en correspondance sur covariante. Comparez ceci aux Functor
s, qui n'ont qu'un seul paramètre (f :: * -> *
) qui peut être mappé de manière covariante. Par exemple, pensez à l'instance Functor
habituelle de Either
. Il ne vous permet que de fmap
sur le second paramètre de type - Right
valeurs sont mappées, Left
valeurs restent telles quelles.
instance Functor (Either a) where
fmap f (Left x) = Left x
fmap f (Right y) = Right (f y)
Cependant, son instance Bifunctor
vous permet de cartographier les deux moitiés de la somme.
instance Bifunctor Either where
bimap f g (Left x) = Left (f x)
bimap f g (Right y) = Right (g y)
De même pour tuples: Functor
exemple de (,)
vous permet de cartographier la deuxième composante, mais Bifunctor
vous permet de cartographier les deux parties.
instance Functor ((,) a) where
fmap f (x, y) = (x, f y)
instance Bifunctor (,) where
bimap f g (x, y) = (f x, g y)
Notez que Maybe
, que vous avez mentionné, ne rentre pas dans le cadre de bifoncteurs parce qu'il n'a qu'un seul paramètre.
Sur la question de Fix
, le point fixe d'un bifoncteur vous permet de caractériser les types récursifs qui ont un paramètre de type fonctorielle, comme la plupart des structures de type conteneur. Utilisons les listes comme exemple.
newtype Fix f = Fix { unFix :: f (Fix f) }
data ListF a r = Nil_ | Cons_ a r deriving Functor
type List a = Fix (ListF a)
En utilisant la norme fonctorielle Fix
, comme je l'ai ci-dessus, il n'y a pas de dérivation générique d'une instance de Functor
pour List
, parce Fix
ne sait rien au sujet de paramètre d » List
a
. C'est, je ne peux pas écrire quelque chose comme instance Something f => Functor (Fix f)
parce que Fix
a le mauvais type.Je dois tourner la manivelle à la main un map
pour les listes, en utilisant peut-être cata
:
map :: (a -> b) -> List a -> List b
map f = cata phi
where phi Nil_ = Fix Nil_
phi Cons_ x r = Fix $ Cons_ (f x) r
La version bifunctorial de Fix
ne permet une instance de Functor
. Fix
utilise l'un des paramètres du bifoncteur pour brancher l'occurrence récursive de Fix f a
et l'autre pour représenter le paramètre fonctorial du type de données résultant.
newtype Fix f a = Fix { unFix :: f a (Fix f a) }
instance Bifunctor f => Functor (Fix f) where
fmap f = Fix . bimap f (fmap f) . unFix
Nous pouvons écrire:
deriveBifunctor ''ListF
type List = Fix ListF
et obtenir l'instance Functor
gratuitement:
map :: (a -> b) -> List a -> List b
map = fmap
Bien sûr, si vous voulez travailler génériquement avec des structures récursives avec plus d'un paramètre alors vous devez généraliser à tri-functors, quad-foncteurs, etc ... Ceci est clairement pas durable, et beaucoup de travail (dans des langages de programmation plus avancés) a été mis dans la conception mo des systèmes flexibles pour caractériser les types.
Puis-je demander quel genre de travail dans quelles sortes de langages de programmation? Pouvez-vous indiquer quelque chose d'accessible? J'ai pensé qu'il pourrait être possible de définir quelque chose comme covariant classe (n :: Nat) p exprimant que p est covariant dans son paramètre n, mais je ne suis pas sûr de ce que cela ressemblerait . – dfeuer
Merci pour l'explication claire! Je pensais que les bifoncteurs étaient des sucres syntaxiques superflus, mais votre exemple de carte de surcharge pour prendre deux paramètres montre à quel point ils sont en réalité beaucoup plus simples sémantiquement. Cependant, je suis également intrigué par ce que vous avez mentionné dans votre commentaire à la fin. OCaml n'a-t-il pas de foncteurs polymorphes? –
@dfeuer Oh, je faisais juste référence à la constellation des descriptions de type de données "univers" qui ont été développées dans les langues DT. –