2016-09-29 2 views
0

J'ai le type de données suivantes:Déclaration de Functor avec plusieurs types?

data Users id height weight = User id height weight 

instance Functor Users where 
fmap f (User id height weight) = User(f id height weight) 

Pourtant, ce ne compilera pas?

Il fonctionne très bien lorsque j'utilise un type avec un seul paramètre, comme:

data Users id = User id 
instance Functor Users where 
fmap f (User id) = User (f id) 

Pourquoi pas mon premier exemple de réalisation?

+0

Le deuxième exemple ne fait pas ce que vous pensez - vous avez besoin d'une indentation sur 'fmap' pour le faire partie de l'instance. Le premier exemple vous avez omis l'erreur qui vous indique le problème (n.b. C'est un problème de genres, les instances de foncteurs sont de type '* -> *'). –

+0

'Pourtant, cela ne compilera pas?' Quelle est l'erreur du compilateur? –

Répondre

6

Chaque constructeur de type et de type a un type. Quelque chose de simple comme Int a genre *. Votre constructeur de type à un seul argument Users a le type * -> *; il prend un type et renvoie un nouveau. Votre premier exemple de Users a le type * -> * -> * -> *; il faut trois types et renvoie un nouveau.

Functor fonctionne uniquement avec les constructeurs de type de type * -> *. Cela vous permet de définir une instance Functor pour votre deuxième constructeur de type Users, mais pas votre premier. Réfléchissez à votre premier essai: le constructeur de données Users prend trois arguments, mais votre définition de fmap tente de l'appeler avec un seul, la valeur de retour de f. Vous pourriez faire Users un foncteur aussi longtemps que vous êtes prêt à faire tous les trois champs du même type:

data Users a = Users a a a 

instance Functor Users where 
    fmap f (Users a b c) = Users (f a) (f b) (f c) 

En théorie, vous pouvez définir une classe Trifunctor (il y a une disposition classe Bifunctor):

class Trifunctor f where 
    trimap :: (a1 -> b1) -> (a2 -> b2) -> (a3 -> b3) -> f a1 a2 a3 -> f b1 b2 b3 

data Users a b c = Users a b c 

instance Trifunctor Users where 
    trimap f g h (Users a b c) = Users (f a) (g b) (h c) 

mais il est discutable à quel point ce serait utile. Functor est utile pour les conteneurs à usage général, car ils ont un large éventail d'utilisations. Users, d'autre part, semble assez spécifique. Vous n'avez généralement pas besoin de la flexibilité avec laquelle vous le définissez; data User = User Int Int Int semble fonctionner correctement, et il n'est pas nécessaire de mapper une fonction par-dessus: à quelle fréquence avez-vous besoin de la même fonction pour modifier la hauteur, le poids et l'âge de la même manière?

+0

Y a-t-il donc un moyen d'appliquer un foncteur à mon premier exemple? –

+0

Voir ma dernière mise à jour: quelle fonction envisagez-vous d'être utile pour la taille, le poids, * et * l'âge d'un utilisateur? – chepner

+0

Merci - ce n'est pas vraiment un cas de «utile», plus d'essayer de comprendre ce que les fonctions/foncteurs applicatifs peuvent faire et où ils peuvent être utiles ... –