Venir avec des (.) . (.)
est en fait assez simple, c'est l'intuition derrière ce qu'il fait c'est assez difficile à comprendre.
(.)
vous fait de très loin lors de la réécriture de l'expression dans le "pipe" style calculs (pensons |
de la coquille). Cependant, il devient difficile de le faire lorsque vous essayez de composer une fonction qui prend plusieurs arguments d'une fonction qui ne prend qu'un seul. Comme exemple, nous allons avoir une définition de l' concatMap
:
concatMap :: (a -> [b]) -> [a] -> [b]
concatMap f xs = concat (map f xs)
Se débarrasser de l' xs
est juste une opération standard.
concatMap f = concat . map f
Cependant, il n'y a pas "gentil" la façon de se débarrasser d' f
. Ceci est causé par le fait, que map
prend deux arguments et nous aimerions appliquer concat
sur son résultat final.
Bien sûr, vous pouvez appliquer un peu de pointfree astuces et de s'en tirer avec juste (.)
:
concatMap f = (.) concat (map f)
concatMap f = (.) concat . map $ f
concatMap = (.) concat . map
concatMap = (concat .) . map
Mais hélas, la lisibilité de ce code est pour la plupart disparu. Au lieu de cela, nous introduisons une nouvelle combinator, qui fait exactement ce dont nous avons besoin: appliquer la deuxième fonction du résultat final de la première.
-- .: is fairly standard name for this combinator
(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
(f .: g) x y = f (g x y)
concatMap = concat .: map
Fine, c'est pour la motivation. Mettons-nous à la pointfree d'affaires.
(.:) = \f g x y -> f (g x y)
= \f g x y -> f ((g x) y)
= \f g x y -> f . g x $ y
= \f g x -> f . g x
Maintenant, voici la partie intéressante. C'est encore un autre de la pointfree astuces qui permet généralement lorsque vous êtes coincé: nous réécrire .
dans son préfixe de la forme et essayer de continuer à partir de là.
= \f g x -> (.) f (g x)
= \f g x -> (.) f . g $ x
= \f g -> (.) f . g
= \f g -> (.) ((.) f) g
= \f -> (.) ((.) f)
= \f -> (.) . (.) $ f
= (.) . (.)
Comme pour l'intuition, il y a ce très bel article que vous devez lire. Je vais paraphraser la partie sur (.)
:
Nous allons réfléchir à nouveau sur ce qui devrait nos combinator faire: il doit s'appliquent f
à la suite du résultat de l' g
(j'ai été en utilisant résultat final de la partie avant sur le but, c'est vraiment ce que vous obtenez lorsque vous appliquer pleinement - modulo unifier les variables de type avec un autre type de fonction - l' g
de la fonction, le résultat ici est juste application g x
pour certains x
).
Ce que cela signifie pour nous d'appliquer f
à la suite de l' g
? Eh bien, une fois que nous appliquons g
de la valeur, nous allons prendre la suite et s'appliquent f
pour elle. Semble familier: c'est ce qu' (.)
n'.
result :: (b -> c) -> ((a -> b) -> (a -> c))
result = (.)
Maintenant, il s'avère que la composition (nos de mot) de ces combinators est juste une fonction de la composition, qui est:
(.:) = result . result -- the result of result