¿Cómo se puede usar id (a -> a) como primer parámetro para desencajar, que requiere una función (a -> b -> c)?
En realidad, uncurry
requiere (a -> (b -> c))
function. ¿Puedes ver la diferencia? :)
Omitir paréntesis es malo (bueno, a veces). Hace que sea imposible para un novato descifrar Haskell. Por supuesto, después de haber reunido algo de experiencia con el idioma, sientes que ya no los necesitas.
En este caso, todo se aclara una vez que escribimos todos los paréntesis omitidas volver explícitamente:
uncurry :: (a -> (b -> c)) -> ((a,b) -> c)
id :: a -> a
Ahora, escribiendo uncurry id
llamadas para una unificación tipo de a1 -> a1
con a2 -> (b -> c)
. Esto es sencillo, a1 ~ a2
y a1 ~ (b -> c)
. Sólo cosas mecánicas, no hay pensamiento creativo involucrado aquí. Así que id
en cuestión tiene realmente el tipo a -> a where a ~ (b -> c)
, y así uncurry id
tiene el tipo (b -> c,b) -> c
, por simple sustitución de a ~ (b -> c)
en (a,b) -> c
. Es decir, espera un par de una función b -> c
y un valor b
, y debe producir un valor de c
.
Dado que los tipos son más general (es decir, no se sabe nada acerca de ellos, y lo que no hay funciones específicas para llamar que podrían hacer el truco de alguna forma especial), el única manera para producir un valor c
aquí es llame a la función b -> c
con el valor b
como argumento. Naturalmente, eso es lo que hace ($)
. Así que uncurry id == uncurry ($)
, aunque id
es sin duda no($)
.
Gracias! ¡Eso está comenzando a tener sentido! ¡Todavía lo encuentro un poco como un spinout! – ssanj
@ssanj: Si te sirve de consuelo, escribir esto como 'currir id' en lugar de'currir ($) 'es malo :) – ehird
Y si quieres ser particularmente malvado, podrías escribir' (\ 'id \' 3) 'en lugar de' ($ 3) 'o defina' id' como 'infixr 0 \' id \ '' y úselo en lugar de '($)', como '(^ 2) \' id \ '1 + 2 * 3'. – Vitus