0votos

Distancia euclídea en Haskell

por josejuan hace 6 años

Free point.

Reto especialmente sencillo consistente en realizar una función que calcule la distancia euclídea entre dos puntos dados.

1
distancia = ((sqrt.sum).).zipWith((^2).(-)) 
5 comentarios
0votos

Escrito por drabor hace 6 años

Me da un error en la composición (^2).(-)
¿No tendría (-) que recibir un solo argumento para que funcionase con .?
0votos

Escrito por josejuan hace 6 años

La función (-) recibe dos argumentos Y DEVUELVE UNO, ese uno, es que se "envía" a la función (^2).

Así, (-) sigue recibiendo sus dos argumentos (provenientes de zipWith) cuyo resultado es enviado a la función currificada (^2).

Prelude> :t (-)
(-) :: Num a => a -> a -> a

Prelude> :t (^)
(^) :: (Integral b, Num a) => a -> b -> a

Prelude> :t (^2)
(^2) :: Num a => a -> a

Prelude> :t (^2).(-)
(^2).(-) :: (Num a, Num (a -> a)) => a -> a -> a

0votos

Escrito por drabor hace 6 años

Gracias por la aclaración, la duda estaba en que siendo (.) del tipo
(.) :: (b -> c) -> (a -> b) -> a -> c

¿no tendría que ser?
(.) :: (c -> d) -> (a -> b -> c) -> a -> d

Pero ahora viendo Num (a -> a) que me suena raro, mejor retomo la lectura de la guía de haskell
1votos

Escrito por josejuan hace 6 años

"ahora viendo Num (a -> a) que me suena raro"

Es una buena pregunta, no parece trivial de ver directamente.

Lo que está ocurriendo es que, como una función en Haskell es como cualquier otro valor (ej. un entero), nada impide que el tipo (no definido) "a" en la firma de la función composición (.) sea, precisamente, una función.

No deben de confundirnos los nombres genéricos que aparecen en las firmas, el "a" de la firma (.) no tiene porqué tener nada que ver con el "a" de las firmas de otras funciones.

En concreto, tenemos que:

Prelude> :t (-)
(-) :: Num a => a -> a -> a


por otro lado

Prelude> :t (^2)
(^2) :: Num a => a -> a


y por último

Prelude> :t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c


al hacer (^2).(-), en realidad estamos forzando a que la última firma sea (sustituyendo, simplemente)

(^2).(-) :: (a -> a) -> ((a -> a) -> a) -> ((a -> a) -> a)


la razón de que al final aparezca (a -> a -> a) y no ((a -> a) -> a) es por cómo (.) aplica las dos funciones anteriores.

Lo suyo es ver su código fuente, que es:

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


y entonces, se ve que el parámetro "x" tiene que emparejarse con el parámetro del operador "-" y por tanto, el lambda que devuelve precisamente (.) es del tipo "a -> a -> a" (y no del tipo "(a -> a) -> a").

;)
0votos

Escrito por drabor hace 6 años

Muchas gracias de nuevo por la explicación!
La verdad es que cuesta asimilarlo, a ver si me pongo por la mañana con ello

Comenta la solución

Tienes que identificarte para poder publicar tu comentario.