
Bonjour,
Merci de vos réponses, la suite dans le texte :
Le 21 décembre 2013 02:57, Alp Mestanogullari
Ça signifie donc que les types n'ayant pas ou plusieurs paramètre de type
ne peuvent pas être utilisé dans cette fonction ? Comme Either ?
Bah comme je le dis justement entre parenthèses, pour Either, il y a un problème au niveau des "kinds" (grosso modo les type des types). Au vu de la gueule d'Applicative, 'f' ne doit prendre qu'un type en paramètre. Mais 'f' peut être un type paramétré à 45 paramètres, les 44 premiers étant fixés à des types précis ou pas forcément:
Une sorte de fonction curryfiée à laquelle il manquerait un paramètre ?
data Blah a b c d = Blah
instance Applicative (Blah a b c) where ...
data Foo a b c = Foo
instance Applicative (Foo Int String) where -- ça nécessite {-# LANGUAGE FlexibleInstances #-}, je peux t'expliquer pourquoi si ça t'intéresse. ...
Je veux bien.
Et donc, si tu donnes un premier paramètre à Either et que tu laisses varier le second, tu obtiens un Applicative :-)
C'est plus clair ?
Oui
L'exemple des erreurs dont parle Valentin est en fait assez simple si on arrive à se focaliser sur chaque truc un à un.
Déjà, Lift:
data Lift f a = Pure a | Other (f a)
On va considérer Lift appliqué un 'f' donné, par exemple Maybe.
data LiftMaybe a = Pure a | Other (Maybe a)
Donc c'est comme si on avait collé tous les 'Maybe a' avec les 'a' tout court, en disant quand même qu'on se rappelle d'où chacun vient grâce aux constructeurs. Tu noteras que le constructeur "Pure" qui apparait par magie, il coincide *EXACTEMENT* avec la fonction "pure" de Applicative, appliquée pour 'f' = 'Lift':
instance Applicative (Lift f) where -- pure :: a -> Lift f a pure x = Pure x ...
Maintenant, pour l'histoire d'erreurs. Le foncteur "Constant" c'est :
data Constant a b = Constant { getConstant :: a }
Et son instance d'Applicative est un exercise assez simple et intéressant selon ta familiarité avec ces derniers. Dans tous les cas, t'as bien compris que le 'b' allait pas servir à grand chose.
Autrement dit, ça prend deux types en paramètre, ça ignore le deuxième et stocke juste une valeur du premier type. Maintenant, Errors:
type Errors e = Lift (Constant e) -- équivalent à type Errors e a = Lift (Constant e) a -- à son tour "moralement équivalent à" : data Errors e a = Pure a | Other (Constant e)
'e' étant un type représentant une erreur (comme String ou une liste de String ou quoi).
Maintenant, les instances pour Lift devraient t'aider à comprendre, en te disant que Errors rajoute aux valeurs "normales" (Pure, qui peut contenir un truc de n'importe quel type!) des valeurs d'erreur. Donc si avait t'avais des fonctions qui balançaient des erreurs à coups de 'error' et que maintenant tu veux faire ça plus joliement, il te suffit d'utiliser 'pure'/'Pure' pour balancer tes valeurs normales dans un 'Errors e a', et d'utiliser failure pour signaler une erreur. Essaye ensuite de voir comment tout cela se passe si tu fixes 'e' et 'a' sur des types précis, [String] et Int respectivement par exemple.
Je vois mieux, mais du coup, quel est l'avantage par rapport à un Either ?
Le 21 décembre 2013 08:13, Arnaud Bailly
Bonjour Gautier,
Personnellement, la lecture de ce papier http://strictlypositive.org/IdiomLite.pdf m'a aidé à mieux comprendre les foncteurs applicatifs. Il montre très bien que le principal intérêt de ces structures c'est de pouvoir écrire des fonctions plus génériques, comme à peu près toutes les structures en Haskell d'ailleurs...
En fait mon soucis c'est de trouver comment l'appliquer au-delà des structures "triviale" (IO, Maybe, List, etc.) Une autre chose qui m'a beaucoup aidé c'est de comprendre le système de
type de Haskell de manière plus détaillée. Tu peux voir du côté du livre de Benjamin Pierce, par exemple. Une des portes d'entrée possible, c'est de voir que le système de types est lui aussi fonctionnel : tu as des valeurs (les types) et des fonctions (les constructeurs de types), ces derniers pouvant être "currifiés". Et tu peux appliquer ces objets les uns aux autres selon leur "genre" (kind) qui est le "système de types" des types :-)
Lequel de ses livres ? Quand je tombe sur quelque chose comme :
instance Applicative (Lift f) where
Cela signifie-t-il "pour tout type Lift encapsulant un type quelconque 'f', je définis les fonction de son typeclass Applicative" ? Du coup le Alternative sont un sorte de Monoïde pour les Applicative ? Il faut qu'il y en ai un de bon sur un couple ou un ensemble, c'est ça ? Ça sert à définir une valeur par défaut, si je comprends. Merci par avance pour vos réponses (on touche au but).