107 votes

L'Opérateur de point en Haskell: besoin de plus d'explication

J'essaie de comprendre ce que l'opérateur point est en train de faire dans ce code Haskell:

sumEuler = sum . (map euler) . mkList

Le code source complet est ci-dessous.

Ma compréhension

L'opérateur point est de prendre les deux fonctions sum et le résultat d' map euler et le résultat d' mkList que l'entrée.

Mais, sum n'est pas une fonction, c'est l'argument de la fonction, non? Donc ce qui se passe ici?

Aussi, qu'est - (map euler) ?

Code

mkList :: Int -> [Int]
mkList n = [1..n-1]

euler :: Int -> Int
euler n = length (filter (relprime n) (mkList n))

sumEuler :: Int -> Int
sumEuler = sum . (map euler) . mkList

160voto

jrockway Points 23734

Mis simplement, . est fonction de la composition, tout comme en mathématiques:

f (g x) = (f . g) x

Dans votre cas, vous êtes la création d'une nouvelle fonction, sumEuler , qui pourrait également être défini comme ceci:

sumEuler x = sum (map euler (mkList x))

Le style dans votre exemple est appelé "point-gratuit" style -- les arguments de la fonction sont omis. Cela rend le code plus clair dans de nombreux cas. (Il peut être difficile de grok la première fois que vous voyez, mais vous vous habituerez à ça après tout. C'est une commune Haskell idiom.)

Si vous êtes encore confus, il peut aider à relater . de quelque chose comme un pipe UNIX. Si f's de sortie devient gs'entrée, dont la sortie est hs'entrée, vous auriez du écrire que sur la ligne de commande comme f < x | g | h. En Haskell, . fonctionne comme UNIX |, mais "à l'envers" -- h . g . f $ x. Je trouve cette notation pour être tout à fait utile quand, par exemple, le traitement d'une liste. À la place de certaines lourd de construction comme map (\x -> x * 2 + 10) [1..10], vous pouvez simplement écrire (+10) . (*2) <$> [1..10]. (Et, si vous voulez seulement d'appliquer cette fonction à une seule valeur; c'est (+10) . (*2) $ 10. Compatible!)

Le Haskell wiki a un bon article avec plus de détails: http://www.haskell.org/haskellwiki/Pointfree

35voto

Jesse Rusak Points 33702

L' . exploitant met en place des fonctions. Par exemple,

a . b

a et b sont des fonctions est une nouvelle fonction qui s'exécute b sur ses arguments, puis un sur ces résultats. Votre code

sumEuler = sum . (map euler) . mkList

est exactement la même chose que:

sumEuler myArgument = sum (map euler (mkList myArgument))

mais j'espère que plus facile à lire. La raison il y a des parenthèses autour de la carte d'euler est parce que c'est plus clair qu'il y a 3 fonctions composées: somme, carte d'euler et mkList - carte d'euler est une fonction unique.

Edit: supprimé des informations erronées au sujet de la préséance.

30voto

Chris Conway Points 24671

sum est une fonction dans le Haskell Prélude, pas un argument pour sumEuler. Il a le type

Num a => [a] -> a

La fonction de la composition de l'opérateur . a type

(b -> c) -> (a -> b) -> a -> c

Nous avons donc

sum                        :: Num a => [a] -> a
map                        :: (a -> b) -> [a] -> [b]
euler                      :: Int -> Int
mkList                     :: Int -> [Int]
(map euler)                :: [Int] -> [Int]
(map euler) . mkList       :: Int -> [Int]
sum . (map euler) . mkList :: Int -> Int

Notez que Int est une instance de l' Num.

13voto

John Leidegren Points 21951

L' . l'opérateur est utilisé pour la fonction de composition. Tout comme pour les mathématiques, si vous avez des fonctions f(x) et g(x) f . g devient f(g(x)).

la carte est une fonction intégrée qui applique une fonction à une liste. En mettant la fonction entre parenthèses de la fonction est considérée comme un argument. Un terme pour ce qui est nourrissage. Vous devriez chercher.

Ce qui est n'est que cela prend une fonction avec deux arguments, elle s'applique à l'argument d'euler. (carte d'euler) droit? et le résultat est une nouvelle fonction qui prend un seul argument.

la somme . (carte d'euler) . mkList est essentiellement une façon élégante de mettre tout ça ensemble. Je dois dire, mon Haskell est un peu rouillé, mais peut-être que vous pouvez mettre la dernière fonction vous-même?

4voto

ajm Points 10000

L'opérateur point s'applique la fonction sur la gauche (sum) à la sortie de la fonction sur la droite. Dans votre cas, vous êtes le chaînage de plusieurs fonctions en même temps - vous êtes de passage le résultat d' mkList de (map euler), et en passant ensuite le résultat de l' sum. Ce site a une bonne introduction à plusieurs concepts.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X