[Haskell-fr] Éclaircissement sur les Applicatives

Valentin Robert valentin.robert.42 at gmail.com
Fri Dec 20 22:16:38 UTC 2013


Réponse dans le texte :


2013/12/20 Gautier DI FOLCO <gautier.difolco at gmail.com>

> Bonjour,
>
> Cela fait maintenant quelques mois que je côtoie Haskell, j'arrive presque
> toujours à mes fins, mais cela ne me convient pas, je tente donc de prendre
> le problème à sa racine : la compréhension, ou plutôt l'assimilation des
> concepts. Je pense que j'ai un soucis à ce niveau car je pense plutôt bien
> voir comment tout s'emboîte, mais face au code, je suis incapable de
> l'appliquer ! Je vous laisse juger par vous-même.
> Je vais tenter d'expliquer ma manière de voir les choses de manière aussi
> détaillée que possible via un ensemble d'assertions (notées AN où N est le
> numéro de l'assertion).
> Le typeclass Applicative à la tête suivante :
> class Functor f => Applicative f where
>   pure :: a -> f a
>   (<*>) :: f (a -> b) -> f a -> f b
>   (*>) :: f a -> f b -> f b
>   (<*) :: f a -> f b -> f a
>
> A1 : Ce qui signifie que tout type implémentant ces fonctions doivent
> également implémenter les fonctions de Functor.
> Q1 : quelle est l'intérêt ?
>

Ce n'est pas vraiment par intérêt plutôt qu'une conséquence du fait qu'un
foncteur applicatif a un foncteur sous-jacent. En particulier, le foncteur
est utilisé dans l'implémentation par défaut de (*>) et (<*), et une
instance correcte doit satisfaire la loi :

f <$> x = pure f <*> x

On pourrait s'en passer, mais c'est probablement pratique.


> Nous avons pure :: Applicative f => a -> f a
> A2 : 'f a' signifie de type a implémentant le typeclass f (Applicative
> dans ce cas précis
>

Hmm pas vraiment. `f a` signifie de type `f a`, où `f` est un foncteur
applicatif.


> A3 : Il s'agit "simplement" d'un lifting, d'une encapsulation, grosso-modo
> de donner un paramètre à un constructeur.
>
> Ensuite (<*>) :: Applicative f => f (a -> b) -> f a -> f b
> A4 : prend une fonction et un paramètre dans un "emballage" implémentant
> Applicative et applique cette valeur à cette fonction en retournant le type
> dans un autre "emballage".
> A5 : cette fonction sert dans deux cas : à fournir un moyen de manipuler
> le contenu de "boîtes", "décurryfier" dans le sens passer des arguments au
> fur et à mesure à une fonction.
> Q2 : Y a-t-il d'autres cas d'application.
>

Pas vraiment, c'est juste un "lift" de l'application d'une fonction. Donc à
utiliser quand tu as une fonction à appliquer...

A6 : <* et *> ne servent qu'à appliquer un des arguments.
> Q3 : quels sont les cas d'applications typiques ? j'ai du mal à voir
>

Je ne fais pas assez de Haskell pour savoir où c'est utilisé, mais c'est
probablement passé comme argument à une fonction d'ordre supérieur dans des
cas spéciaux où on n'a pas trop de choix sur le format des données en
entrée et on veut ignorer la moitié...

Ensuite il y a les fonctions de lifting :
>
> liftA :: Applicative f => (a -> b) -> f a -> f b
> A7 : prend une fonction "normale" à un argument et en fait une fonction
> maniant une structure encapsulée.
> Q4 : quel est l'intérêt ? liftA (+1) $ Just 1 n'est pas égale à pure (+1)
> <*> Just 1 ?
>

Si, mais parfois tu as besoin de `pure` et parfois de `liftA`. Encore une
fois, ça dépend de la façon dont c'est utilisé. Évidemment, si tu appliques
tout complètement ça semble redondant, mais quand tu appliques
partiellement, `liftA (+1)` et `pure (+1)` ont un type différent, tous deux
utiles.


>  Q5 : ou à la version Functor : (+1) <$> Just 1 ?
> Q6 : dans le cas de version Functor, quel est l'intérêt de la passer
> Applicative ?
>

Pas d'intérêt : si tout ce dont tu as besoin c'est `fmap`, utilise `fmap`.


> liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
> A8 : idem mais avec deux arguments
> A9 : liftA2 (+) (Just 2) (Just 1) est équivalent à liftA (+) (Just 2) <*>
> Just 1
> Q7 : Quel est l'intérêt du coup ?
>

Même réponse. Tu sembles chercher à éviter toute redondance. Pourquoi ne
pas écrire tout ton code avec juste des lambdas et des applications ? :-)


> liftA3 :: Applicative f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d
> A10 : idem mais avec trois arguments
>
> Q8 : Quel est l'intérêt de Control.Applicative.Lift ?
> Il est écrit : "Adding a new kind of pure computation to an applicative
> functor"
> Q9 : J'ai du mal à saisir cette notion de calcul, est-ce qu'il est
> possible de me  l'expliquer en deux mots ?
>

Je ne saurai expliquer ça clairement, mais tu peux jeter un coup d'oeil ici
:

http://hackage.haskell.org/package/transformers-0.3.0.0/docs/src/Control-Applicative-Lift.html#unLift

En particulier, l'implémentation de `fmap` et le commentaire du type Errors
peuvent te donner une idée de ce qu'il se passe...

Je me rend compte que mon mail est très long, ça fait plus de deux mois que
> je me casse les dents dessus, j'ai écumé plusieurs articles/livres, pas
> moyen de me faire une idée claire de tout ça, ou de voir les applications
> pratiques.
> Je vous serait très reconnaissant de prendre le temps de me répondre et/ou
> de valider/invalider mes assertions,
> Merci par avance.
>
> PS : Par la suite j'aurais des question sur Alternative et les Monades
> PPS : la longueur de la rédaction m'a donné une idée pour Q7 :
> A11 : liftA2 et liftA3 servent à obtenir des fonctions "passables" à des
> fonctions qui le demande, ex :
> myF :: (Maybe a -> Maybe b -> Maybe c) -> a -> b -> Maybe c
> myF f a b = f (Just a) (Just  b)
> la fonction serait appelable via myF (liftA2 (+)) 1 2
>

Exactement !

_______________________________________________
> Haskell-fr mailing list
> Haskell-fr at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-fr
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/haskell-fr/attachments/20131220/5a7af779/attachment-0001.html>


More information about the Haskell-fr mailing list