practico 1 - uso de funciones predefinidas

practico 1 - uso de funciones predefinidas

de Sebastian Guerrero Font -
Número de respuestas: 4

Se pueden usar funciones como filter en la resolucion de ejercicios o la idea es usar en este caso solo comprehension de listas?

Estas dos implementaciones serian equivalentes?

type Curso = ([Char], Int, Int)
type Estudiante = ([Char], Int, Int, [Curso])

cursosNota :: Estudiante -> Int -> [Curso]
cursosNota (_, _, _, c) n = filter (\(_, _, nota) -> nota == n) c           --con filtros

cursosNota (_, _, _, c) n = [x | x <- c, \(_, _, nota) -> nota == n x]     --con list comprehension


Otra duda que tengo es que si cargo ese archivo en el Preludo haciendo un load y depues defino lo siguiente:
*Main> a1 = ("c1", 1, 5)
*Main> a2 = ("c2", 1, 4)
*Main> a3 = ("g1", 1, 5)
*Main> e = ("pablo", 50922, 2015, [a1, a2, a3])

y llamo:

*Main> cursosNota e 5

anda todo bien y devuelve: 

[("c1",1,5),("g1",1,5)]


pero si defino a1, a2, a3 y e en el programa y trato de llamar  cursosNota e 5

me salta un error:

<interactive>:70:12: error:

    • Couldn't match type ‘Integer’ with ‘Int’

      Expected type: Estudiante

        Actual type: ([Char], Integer, Integer,

                      [([Char], Integer, Integer)])

    • In the first argument of ‘cursosNota’, namely ‘e’

      In the expression: cursosNota e 5

      In an equation for ‘it’: it = cursosNota e 5


Trate definirlos tipo:  a1 = ("c1", 1: Int, 5: Int) 

Pero ahi me salto: Data constructor not in scope: Int :: [Integer]


En respuesta a Sebastian Guerrero Font

Re: practico 1 - uso de funciones predefinidas

de Sebastian Guerrero Font -

Bueno con la segunda parte, tenia un error, para definir el tipo son dos : 

Si los defino como:  a1 = ("c1", 1, 5) :: Curso  , anda bien.


Y un error que tenia una funcion que subi: cursosNota (_, _, _, c) n = [x | x <- c, \(_, _, nota) -> nota == n x]

deberia tener parentesis delimitando la funcion anonima:  cursosNota (_, _, _, c) n = [x | x <- c, (\(_, _, nota) -> nota == n) x]

En respuesta a Sebastian Guerrero Font

Re: practico 1 - uso de funciones predefinidas

de Juan Pablo García Garland -

Hola.

Primero comentarte que tus razonamientos no son incorrectos, pero te estás enfrentando a problemas que aparecen cuando uno se ensucia las manos y programa :) : un detalle de la implementación de GHC y una cuestión de sintaxis.

Voy por partes:

Respecto al error:

    • Couldn't match type ‘Integer’ with ‘Int’
      Expected type: Estudiante
        Actual type: ([Char], Integer, Integer,
                      [([Char], Integer, Integer)])

El problema acá es que en una declaración como

a1 = ("c1",1, 5)

Los literales (si no hay mas información de contexto) cuando vienen compilados desde un módulo, en el intérprete (ghci) se infieren de tipo Integer. Esto es una decisión de diseño de los implementadores de GHC y hay razones para que sea así, pero no vamos a entrar en detalles en el curso (usualmente se llama "type defaulting"). Cuando se define a los ai en el intérprete la cosa funciona porque se infiere el tipo más general de a1 que es (Num b, Num c) =&gt; ([Char], b, c) (igual que si llamaras a cursoNota con e como argumento dentro del módulo que definiste).

Importante: cuando se te pregunte por el tipo más general de la expresión a1 tal y como la definiste, es ese, el polimórfico. El "type defaulting" es una excepción en la implementación de GHC, nada más. Tranquilo igual si no sabés todavía inferir ese tipo por tu cuenta, es algo que vas a ir aprendiendo en el correr de las semanas.

Entonces a1 tiene tipo (String,Integer,Integer), y al eventualmente llamar cursosNota con ese argumento los tipos no coinciden. Si se anotan los tipos no va a existir ese problema, por ejemplo

a1 :: Curso
a1 = ("c1",1, 5)

(y lo mismo para a2, a3)

O más compacto:

a1  = ("c1",1, 5) :: Curso

Ahí la información del tipo la provee el programador, y tu ejemplo pasa bien el chequeo de tipos. Tan solo anotando en tipo de e ya es suficiente (el compilador infiere los tipos de los ai a partir de esa expresión).

Otra opción es usar tipos algebraicos, por ejemplo definimos:

data Curso = Curso String Int Int
...
...

a1 = Curso "c1" 1 5

en este caso no vas a tener el problema aunque no anotes los tipos, porque la presencia del constructor Curso da la información necesaria al compilador (el problema pedía usar tuplas, no me estoy olvidando de eso, esto es solo para complementar).

Tu idea de anotar solo subexpresiones, como en:

a1 = ("c1", 1: Int, 5: Int) 

es buena, pero hay un error de sintaxis (dos puntos, en vez de cuatro puntos). El operador : es la concatenación de listas, el compilador cree que 1 : Int es un valor, entonces Int es un valor, y como empieza con mayúscula debe ser un constructor, que no está en scope (eso es lo que quiere decir el error que muestra).

En respuesta a Juan Pablo García Garland

Re: practico 1 - uso de funciones predefinidas

de Sebastian Guerrero Font -

Gracias, por la explicacion, me aclaro bastante. 

Sobre el uso de funciones como filter, esta bien eso o se prefiere que no las usemos?

Y me quedo otra duda con respecto a el ejercicio 7. Ademas, de lo que mencionaste de que al usar data para definir Curso y Estudiante se evitan esos posibles problemas que puede tener uno con el compilador, hay alguna ventaja o se simplifica alguna implementacion al usar tipos de datos algebraicos en vez de tuplas? Porque la unica diferencia que encontre al reescribir las funciones es el tener que escribir (Estudiante ... ) en vez de la notacion de tupla, pero despues las implementaciones las veo iguales.

En respuesta a Sebastian Guerrero Font

Re: practico 1 - uso de funciones predefinidas

de Marcos Viera - InCo -

- En este práctico preferimos que usen listas por comprensión, ya se van a utilizar esas funciones en los siguientes prácticos.

- Las implementaciones son iguales, pero las funciones son específicas para estos tipos y no, por ejemplo en el caso de los cursos, para cualquier tripla (String,Int,Int).