Question

Il y a quelque temps, j'ai demandé à un question sur $ et des réponses utiles - en fait, je pensais comprendre comment l’utiliser.

Il semble que je me suis trompé: (

Cet exemple apparaît dans un tutoriel:

instance Monad [] where
   xs >>= f = concat . map f $ xs

Je ne vois pas pourquoi $ a été utilisé là-bas; ghci ne m'aide pas non plus, car même les tests que je fais là semblent montrer une équivalence avec la version qui omettrait simplement le $. Quelqu'un peut-il clarifier cela pour moi?

Était-ce utile?

La solution

Le $ est utilisé ici car sa priorité est inférieure à celle d'une application de fonction normale. Une autre façon d’écrire ce code est la suivante:

instance Monad [] where
   xs >>= f = (concat . map f) xs

L’idée ici est de construire d’abord une fonction ( concat. map f ) puis de l’appliquer à son argument ( xs ). Comme indiqué, cela peut également être fait en mettant simplement des parenthèses autour de la première partie.

Notez que l'omission du $ dans la définition d'origine est impossible, cela entraînera une erreur de type. En effet, l'opérateur de composition de fonction (. ) a une priorité inférieure à l'application de fonction normale transformant effectivement l'expression en:

instance Monad [] where
  xs >>= f = concat . (map f xs)

Ce qui n’a aucun sens, car le deuxième argument de l’opérateur de composition de fonction n’est pas du tout une fonction. Bien que la définition suivante ait un sens:

instance Monad [] where
  xs >>= f = concat (map f xs)

Incidemment, c’est aussi la définition que je préférerais, car elle me semble beaucoup plus claire.

Autres conseils

Je voudrais expliquer pourquoi IMHO ce n'est pas le style utilisé ici:

instance Monad [] where
  xs >>= f = concat (map f xs)

concat. map f est un exemple d'écriture dite de type point-free; où pointfree signifie "sans le point d'application". Rappelez-vous qu'en maths, dans l'expression y = f (x) , on dit que f est appliqué sur le point x . Dans la plupart des cas, vous pouvez réellement effectuer une dernière étape en remplaçant:

f x = something $ x

avec

f = something

comme f = concat. map f , et c'est en fait un style sans points. Ce qui est plus clair est discutable, mais le style sans point donne un point de vue différent qui est également utile, donc est parfois utilisé même lorsque cela n’est pas exactement nécessaire.

EDIT: Après le commentaire d’Alasdair, je devrais remercier.

La raison pour laquelle $ est utilisé ici est due à la signature de type de (.):

(.) :: (b -> c) -> (a -> c) -> a -> c

Ici nous avons

map f :: [a] -> [[b]]

et

concat :: [[b]] -> [b]

Nous nous retrouvons donc avec

concat . map f :: [a] -> [b]

et le type de (.) pourraient être écrits comme

(.) :: ([[b]] ??- > [b]) - > ([a] - > [[b]]) - > [a] - > [b]

Si nous devions utiliser concat. map f xs , on verrait que

map f xs :: [[b]]

Et ne peut donc pas être utilisé avec (.). (le type doit être (.) :: (a - > b) - > a - > b

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top