2012-02-11 25 views
9

lectura "Real World Haskell", en la página 95 el autor proporciona un ejemplo:La función obtiene cuatro argumentos en lugar de tres: ¿por qué no se rompe esto?

myFoldl f z xs = foldr step id xs z 
    where step x g a = g (f a x) 

Mi pregunta es: ¿Por qué se compila el código? foldr toma solo tres argumentos, pero aquí se pasa a cuatro: step, id, xs, z.

Por ejemplo, esto no funciona (porque suma espera uno):

sum filter odd [1,2,3] 

lugar tengo que escribir:

sum $ filter odd [1,2,3] 

Respuesta

12

Este es el tipo de foldr:

Prelude> :t foldr 
foldr :: (a -> b -> b) -> b -> [a] -> b 

¿Se puede averiguar cómo se convierte en una función de cuatro argumento? ¡Hagamos un intento!

  1. lo estamos dando id :: d -> d como segundo parámetro (b), así que vamos a sustitutos que en el tipo:

    (a -> (d -> d) -> (d -> d)) -> (d -> d) -> [a] -> (d -> d) 
    
  2. en Haskell, a -> a -> a es lo mismo que a -> (a -> a), lo que nos da (eliminando el último par de paréntesis):

    (a -> (d -> d) -> (d -> d)) -> (d -> d) -> [a] -> d -> d 
    
  3. vamos a simplificar, sustituyendo e para (a -> (d -> d) -> (d -> d)) y f para (d -> d), para que sea más fácil de leer:

    e -> f -> [a] -> d -> d 
    

Por lo que podemos ver claramente que hemos construido una función de cuatro discusión! Me duele la cabeza.


Aquí es un ejemplo más simple de crear una función de n + 1-argumento de una func n-arg:

Prelude> :t id 
id :: a -> a 

id es una función de un argumento.

Prelude> id id id id id 5 
5 

Pero acabo de darle 5 args!

+0

No entiendo por qué puede hacer 'id id 5', pero no puede hacer:' foo x = x + 1; bar y = y + 1; foo bar 1'? – drozzy

+4

@drozzy: se trata de tipos y polimorfismo. Tome 'id :: a -> a': puede sustituir * cualquier * tipo por' a'. Sin embargo, 'foo' es diferente, porque tiene restricciones: necesita un número:' foo :: (Num a) => a -> a'. 'bar :: (Num a) => a -> a' no es una instancia de la clase de tipo' Num' y por lo tanto no satisface la restricción '(Num a)' de 'foo'. –

+2

@drozzy ¡Quizás ayude si clarificamos la asociatividad de la aplicación de la función! Recuerde que 'id id 5' se analiza como' (id id) 5' - es decir, da 'id' como argumento a' id' primero, y luego '5' como argumento para el resultado - no como' id (id 5) '. –

10

Es debido a la forma polimórfica foldr es:

foldr :: (a -> b -> b) -> b -> [a] -> b 

Aquí, hemos instanciado b a un tipo de función, llamémoslo c -> c, por lo que el tipo de foldr especializa a (por ejemplo)

foldr :: (a -> (c -> c) -> (c -> c)) -> (c -> c) -> [a] -> c -> c 
+1

También podría señalar que el elemento neutral en la pregunta original ya es una función, 'id'. – ShiDoiSi

9

foldr sólo toma 3 argumentos

incorrecto. Todas las funciones en Haskell toman exactamente 1 argumento y producen exactamente 1 resultado.

foldr :: (a -> b -> b) -> b -> [a] -> b 

Sede, foldr toma un argumento (a -> b -> b), y produce 1 resultado: b -> [a] -> b. Cuando vea esto:

foldr step id xs z 

Recuerde, es sólo la taquigrafía para esto:

((((foldr step) id) xs) z) 

Esto explica por qué esto es un disparate:

sum filter odd [1,2,3] 
(((sum filter) odd) [1,2,3]) 

sum :: Num a => [a] -> a toma una lista como su entrada, pero le diste una función.

Cuestiones relacionadas