tuplas sobre simbolos opciones multiplos multiplicar hacer funciones funcion ejemplos drop como haskell syntax function-composition

sobre - multiplicar haskell



Operador de puntos en Haskell: necesito más explicaciones (6)

Operador de puntos en Haskell

Estoy tratando de entender lo que el operador de punto está haciendo en este código Haskell:

sumEuler = sum . (map euler) . mkList

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 para map :

map_euler = map euler sumEuler = sum . map_euler . mkList

Ahora solo tenemos los puntos. ¿Qué es indicado por estos puntos?

De la fuente :

(.) :: (b -> c) -> (a -> b) -> a -> c (.) f g = /x -> f (g x)

Por lo tanto, (.) Es el operador de redacción .

Componer

En matemáticas, podríamos escribir la composición de funciones, f (x) yg (x), es decir, f (g (x)), como

(f ∘ g) (x)

que puede leerse "f compuesto con g".

Entonces en Haskell, f ∘ g, o f compuesto con g, puede escribirse:

f . g

La composición es asociativa, lo que significa que f (g (h (x))), escrita con el operador de composición, puede omitir el paréntesis sin ninguna ambigüedad.

Es decir, dado que (f ∘ g) ∘ h es equivalente a f ∘ (g ∘ h), simplemente podemos escribir f ∘ g ∘ h.

Dando vueltas

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))

Estoy tratando de entender lo que el operador de punto está haciendo en este código Haskell:

sumEuler = sum . (map euler) . mkList

El código fuente completo está debajo.

Mi entendimiento

El operador punto está tomando las dos funciones sum y el resultado de map euler y el resultado de mkList como entrada.

Pero, la sum no es una función, es el argumento de la función, ¿verdad? Entonces, ¿qué está pasando aquí?

Además, ¿qué está haciendo (map euler) ?

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


El operador de punto aplica la función de la izquierda ( sum ) a la salida de la función de la derecha. En tu caso, estás encadenando varias funciones juntas: pasas el resultado de mkList a (map euler) y luego mkList el resultado de eso a la sum . Este sitio tiene una buena introducción a varios de los conceptos.


En pocas palabras,. es la composición de la función, al igual que en matemáticas:

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

En su caso, está creando una nueva función, sumEuler que también podría definirse así:

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

El estilo en su ejemplo se llama estilo "sin puntos": los argumentos para la función se omiten. Esto hace que el código sea más claro en muchos casos. (Puede ser difícil asimilar la primera vez que lo ves, pero te acostumbrarás después de un tiempo. Es un idioma común de Haskell).

Si todavía está confundido, puede ayudar a relacionarse . a algo así como una tubería UNIX. Si la salida de f convierte en la entrada de g , cuya salida se convierte en la entrada de h , escribiría eso en la línea de comando como f < x | g | h f < x | g | h f < x | g | h . En Haskell,. funciona como el UNIX | , pero "al revés" - h . g . f $ x h . g . f $ x h . g . f $ x . Creo que esta notación es bastante útil cuando, por ejemplo, procesamos una lista. En lugar de una construcción difícil de manejar como el map (/x -> x * 2 + 10) [1..10] , podría escribir (+10) . (*2) <$> [1..10] (+10) . (*2) <$> [1..10] . (Y, si solo desea aplicar esa función a un único valor, es (+10) . (*2) $ 10 ¡Consistente!)

La wiki de Haskell tiene un buen artículo con más detalles: http://www.haskell.org/haskellwiki/Pointfree


Los . el operador compone funciones Por ejemplo,

a . b

Donde a y b son funciones es una nueva función que ejecuta b en sus argumentos, luego 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 cual hay paréntesis alrededor de map euler es porque hace más claro que hay 3 funciones compuestas: sum , map euler y mkList - map euler es una función única.


Los . el operador se usa para la composición de funciones. Al igual que las matemáticas, si tiene que usar 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 currying . Deberías mirar eso.

Lo que hace es que toma una función con decir dos argumentos, aplica el argumento euler. (mapa de euler) ¿verdad? y el resultado es una nueva función, que solo requiere un argumento.

suma (mapa euler). mkList es básicamente una forma elegante de armar todo eso. Debo decir que mi Haskell está un poco oxidado, pero ¿quizás usted mismo puede armar esa última función?


sum es una función en el preludio de Haskell, no un argumento para sumEuler . Tiene el tipo

Num a => [a] -> a

El operador de composición de funciones . tiene tipo

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

Entonces tenemos

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

Tenga en cuenta que Int es una instancia de Num .