Estoy tratando de entender qué está haciendo el operador de puntos en este código de Haskell:
sumEuler = sum . (map euler) . mkList
El código fuente completo está a continuación.
Mi punto de vista
El operador de punto toma las dos funciones sum
y el resultado de map euler
y el resultado de mkList
como entrada.
Pero, sum
¿no es una función, es el argumento de la función, verdad? Entonces, ¿qué está pasando aquí?
Además, ¿qué está (map euler)
haciendo?
Código
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
fuente
f (g x)
=(f . g) x
"?) ¿O algo más?==
lugar, necesitaría si quisiera Haskell estándar válido.Los . operador compone funciones. Por ejemplo,
a . b
Donde un y b son funciones es una nueva función que se ejecuta b en sus argumentos, entonces A en esos resultados. Tu codigo
sumEuler = sum . (map euler) . mkList
es exactamente lo mismo que:
sumEuler myArgument = sum (map euler (mkList myArgument))
pero espero que sea más fácil de leer. La razón por la que hay parens alrededor de map euler es porque deja más claro que se componen 3 funciones: sum , map euler y mkList - map euler es una sola función.
fuente
sum
es una función en Haskell Prelude, no un argumento parasumEuler
. Tiene el tipoNum a => [a] -> a
El operador de composición de funciones
.
tiene tipoEntonces tenemos
euler :: Int -> Int map :: (a -> b ) -> [a ] -> [b ] (map euler) :: [Int] -> [Int] mkList :: Int -> [Int] (map euler) . mkList :: Int -> [Int] sum :: Num a => [a ] -> a sum . (map euler) . mkList :: Int -> Int
Tenga en cuenta que, de
Int
hecho, es una instancia de laNum
clase de tipos.fuente
Los . El operador se utiliza para la composición de funciones. Al igual que con las matemáticas, si tiene que utilizar las funciones f (x) y g (x) f. g se convierte en f (g (x)).
map es una función incorporada que aplica una función a una lista. Al poner la función entre paréntesis, la función se trata como un argumento. Un término para esto es curry . Deberías buscar eso.
Lo que hace es que toma una función con dos argumentos, aplica el argumento euler. (mapa euler) ¿verdad? y el resultado es una nueva función, que solo toma un argumento.
suma. (mapa euler). mkList es básicamente una forma elegante de juntar todo eso. Debo decir que mi Haskell está un poco oxidado, pero ¿tal vez puedas armar esa última función tú mismo?
fuente
Respuesta corta
Código equivalente sin puntos, eso es solo
sumEuler = \x -> sum ((map euler) (mkList x))
o sin la lambda
sumEuler x = sum ((map euler) (mkList x))
porque el punto (.) indica la composición de la función.
Respuesta más larga
Primero, simplifiquemos la aplicación parcial de
euler
amap
:map_euler = map euler sumEuler = sum . map_euler . mkList
Ahora solo tenemos los puntos. ¿Qué indican estos puntos?
De la fuente :
Así
(.)
es el operador de composición .Componer
En matemáticas, podríamos escribir la composición de funciones, f (x) y g (x), es decir, f (g (x)), como
que puede leerse "f compuesta con g".
Entonces en Haskell, f ∘ g, o f compuesta con g, se puede escribir:
f . g
La composición es asociativa, lo que significa que f (g (h (x))), escrito con el operador de composición, puede omitir los paréntesis sin ambigüedad.
Es decir, dado que (f ∘ g) ∘ h es equivalente af ∘ (g ∘ h), simplemente podemos escribir f ∘ g ∘ h.
Dando vueltas hacia atrás
Volviendo a nuestra simplificación anterior, esto:
sumEuler = sum . map_euler . mkList
solo significa que
sumEuler
es una composición no aplicada de esas funciones:sumEuler = \x -> sum (map_euler (mkList x))
fuente
El operador de punto aplica la función de la izquierda (
sum
) a la salida de la función de la derecha. En su caso, está encadenando varias funciones juntas: está pasando el resultado demkList
a(map euler)
y luego pasando el resultado de eso asum
. Este sitio tiene una buena introducción a varios de los conceptos.fuente