2012-01-05 7 views
34

estoy trabajando en las 99 preguntas Haskell y vio una solución para encontrar el último elemento de una lista:el comportamiento de "Identificación const"

myLast = foldr1 (const id) 

del tipo de const es a -> b -> a sino la de const id es b -> a -> a
¿cuál es la magia aquí?

+0

Solo para completar las respuestas provistas, recuerde que todas las funciones en Haskell están al curry, entonces 'a -> (b -> c)' es lo mismo que 'a -> b -> c' –

+0

Hay una [pregunta similar ] (http://stackoverflow.com/questions/18680341/what-is-the-purpose-of-const-id-in-this-function), pero tiene una respuesta más situacional, que podría ser más clara, dependiendo de tu proceso de pensamiento – chwarr

Respuesta

42

El tipo de id es c->c; simplemente devuelve lo mismo que se le da.

El tipo de const es a->b->a. En const id, a convierte c->c, por lo que el tipo de const en este caso se convierte en:

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

Ahora que ya ha aplicado esta función const, es decir, que haya pasado id a él, entonces lo que queda es b -> (c->c).

PS: El tipo de const const id es a->b->a, y el tipo de const const const id es b->a->a, y así sucesivamente!

+0

genial, la magia de dos funciones simples – manuzhang

+0

No es de extrañar, ya que 'const foo bar = foo'. Tenga en cuenta también que 'const id' es lo mismo que' flip const', o 'flip const flip const flip const flip const id const id id';) –

+3

También' id = ap const const'. – augustss

23

No hay magia. La definición de const es:

const :: a -> b -> a 
const x y = x 

y la definición de id es:

id :: a -> a 
id x = x 

Así const id es sólo \y -> id, una función que devuelve siempre id. Y si id es solo \x -> x, entonces const id debe ser el mismo que \y -> \x -> x. Ergo, tiene el tipo b -> (a -> a).

const id también se pueden escribir flip const. Como const es \x -> \y -> x, entonces flip const toma los argumentos en el orden opuesto, \y -> \x -> x, que es lo mismo que const id.

6

Aquí está mi comprensión de cómo funciona esto.

Esta es la explicación más simple que pude pensar, intenté (a propósito) evitar cualquier concepto o palabra potencialmente confuso.

Un concepto importante a tener en cuenta es la aplicación parcial.

La forma en que entiendo esto es que en Haskell podemos "arreglar" uno de los parámetros de la función a un valor conocido, por lo que ahora la función acepta un parámetro menos.

Recapitulación: el tipo de const es:

const :: a -> b -> a 

Como un ejemplo más simple, vamos a “fijar” el primer parámetro a ser (+)

let f = const (+) 

Ahora que nos hemos fijado la primer parámetro de const, "f" es una función que acepta solo un único parámetro. Pero como const siempre devuelve su primer parámetro, que hemos corregido, significa que lo que pasamos a "f" se ignorará, y siempre devolverá la función "+".

Como un ejemplo, toda la siguiente dará 5, ya que f siempre devolverá la función de “+”, independientemente de lo que recibió como primer parámetro, y la función de “+” operará en 2 y 3:

f “aaa”  2 3 
f 904212  2 3 
f undefined 2 3 

El tipo de f es:

f :: b -> Integer -> Integer -> Integer 

Nota que “b” puede ser cualquier cosa, como puede verse más arriba.

Ahora para la función real en cuestión:

g = const id 

Esto significa que “fijos” id como primer parámetro, de manera que el anterior, “g” ignora su primer parámetro y devuelve la función de “id” . En Haskell, podemos seguir adelante y proporcionar el parámetro adicional para “Identificación”, tal como lo hicimos con (+) anterior, así que por ejemplo todos ellos regresarán 42:

g “aaa”  42 
g undefined 42 

Así “g” está aceptando función de dos parámetros, y siempre regresaba al segundo, por lo que su tipo es:

g = const id :: b -> a -> a 

Pero espera un minuto, acabo de hacer un gran salto allí. ¿No debería el tipo ser:

b -> (a -> a) 

dado que acabamos de decir que aceptamos cualquier cosa y devolvemos "id"?

Bueno, sí, excepto que en Haskell esos paréntesis pueden omitirse.
También tiene sentido ya que puede suministrar inmediatamente la función "id" con el parámetro adicional que necesita (como en el ejemplo "const (+)" anterior).

1

La única forma en que finalmente entendí esto fue imaginar la secuencia de pasos que Haskell lleva a cabo para evaluar una expresión como const id 1 2. Primero considere estos enunciados:

En Haskell, todas las funciones se consideran al curry: Es decir, todas las funciones en Haskell toman solo un argumento. 1

Sin embargo, la aplicación funcional se asocia a la izquierda: f x y es realmente (f x) y.1

Con esto en mente, y ver desde arriba que const toma dos argumentos y id toma uno, podemos ver estos pasos:

const id 1 2 -- Haskell evaluates 'const id' and returns a function (we can call it 
       -- 'constId') which accepts one argument and always returns 'id' 

constId 1 2 -- Haskell now evaluates 'constId 1', which as expected just returns 'id' 

id 2   -- 'id' is now applied to 2, which just returns '2' 

2    -- final result 

responsabilidad: Soy nuevo en Haskell.

Cuestiones relacionadas