Ejercicio 6 - práctico 2

Ejercicio 6 - práctico 2

de Santiago Guridi Barreto -
Número de respuestas: 4

Buenas,

En este ejercicio entiendo que (dup . dup) y (dup dup) no son lo mismo así como también el uso que se le puede dar a (dup . dup).

No me queda claro de que manera se puede computar algo con (dup dup) siendo que su tipo segun Haskell es: (dup dup) :: (b -> (b, b), b -> (b, b)). Es decir, como se usaría (dup dup) si es que tiene algún uso? Tampoco me queda claro si eso es en definitiva una función o no.

Gracias desde ya,

Saludos,

Santiago.

En respuesta a Santiago Guridi Barreto

Re: Ejercicio 6 - práctico 2

de Marcos Viera - InCo -

Hola,

Como bien dijiste, (dup dup) tiene tipo 

(dup dup) :: (a -> (a,a), a -> (a,a))

es decir que la aplicación retorna un par de funciones (dup).

Supongamos que tengo una definición:

pardup = dup dup

dado que es un par, si quiero usar sus componentes los puedo obtener ya sea con pattern matching o con fst y snd. Por ejemplo:

> fst pardup 5

(5,5)

saludos

En respuesta a Marcos Viera - InCo

Re: Ejercicio 6 - práctico 2

de Rodrigo Alain De La Vega Rodriguez -
Buenas! Yo de esto no entiendo mucho lo que esta pasando.
Si hago dup . dup estoy haciendo dup(dup x) y eso me devuelve (x,x) lo cual para mi es correcto. Luego si veo su tipo con :t dup(dup) que es igual a hacer dup . dup me devuelve el mismo tipo que dup dup pero la diferencia es que si hago dup dup x no funciona (me da error) y si hago (dup dup) x tampoco.
Supongo que la primera funciona porque al estar parentizado Haskell entiende que tiene que aplicar un dup y utiliza la definición que da la letra del ejercicio y supongo que el otro no anda porque esta usando el tipo que mencione antes el cual no recibe parámetros de entrada no?

No se si se entendió. Gracias!
En respuesta a Rodrigo Alain De La Vega Rodriguez

Re: Ejercicio 6 - práctico 2

de Alberto Pardo -
Hola,

Lo que sucede es que (dup dup) corresponde a la duplicación de la función dup. Como dup es polimórfica,

dup :: a -> (a,a)
dup x = (x,x)

le puedo pasar cualquier cosa como argumento, en particular la propia función dup. Por lo tanto (dup dup) retorna el par (dup,dup) que tiene tipo (a -> (a,a), a -> (a,a)). A pesar que el par resultante contiene funciones en sus componentes, no lo puedo aplicar directamente a un valor. Puedo aplicar alguna de esas funciones del par si primero las extraigo del par. Por ejemplo, puedo hacer lo que había dicho Marcos:

fst (dup dup) 5 retorna (5,5)

o sea, extraemos la función que está en la primera componente del par (dup,dup) haciendo fst (dup dup), eso me da como resultado la propia función dup; por último aplico dup a 5, resultando en (5,5).

Otro ejemplo, Para poder aplicar (dup,dup) "directamete" debo definir una función que aplique pares de funciones a pares de argumentos:

app2 (f,g) (x,y) = (f x,g y)

Luego puedo hacer: app2 (dup,dup) (3,4), que retorna ((3,3),(4,4)).

Finalmente, la expresión (dup dup) es permitida debido al polimorfismo. En esa expresión estamos usando 2 instancias diferentes de dup. Voy a escribir la expresión como (dup_1 dup_2) para que sea mas sencilla la explicación. Dado que el tipo de dup :: a -> (a,a) es polimórfico, podemos tener ocurrencias de dup sobre distintos tipos "a". Supongamos que dup_2 es la instancia que manipula objetos de tipo t, por lo que dup_2 :: t -> (t,t). Si es así entonces dup_1 es la instancia de dup que está tomando como entrada objetos de tipo t -> (t,t) (o sea funciones):

dup_2 :: (t -> (t,t)) -> (t -> (t,t), t -> (t,t))

A pasarle dup_1 es que finalmente se arma la expresión (dup_1 dup_2) que retorna el par:

(dup_2,dup_2) :: (t -> (t,t), t -> (t,t))

Saludos,
Alberto.