Autor Tema: Inferir el tipo de la siguiente función (Haskell)

0 Usuarios y 1 Visitante están viendo este tema.

26 Mayo, 2021, 09:40 am
Leído 2558 veces

manooooh

  • $$\Large \color{#9c57a6}\pi\,\pi\,\pi\,\pi\,\pi\,\pi$$
  • Mensajes: 4,791
  • País: ar
  • Karma: +1/-0
  • Sexo: Masculino
Hola!

Creo este espacio con la intención de que sea colaborativo y abierto para todo aquel que sepa programar en Haskell, un lenguaje que se basa bastante en las matemáticas que todos conocemos, con sus particularidades.

Nos piden inferir qué tipo tiene la siguiente función:

Código: [Seleccionar]
g a b = b.head.map (\(_,c) -> menor a c).filter (even.fst)
Estoy bastante perdido, básicamente por todos los símbolos y composiciones que podemos ver. No quiero tocar una terminal como para no tentarme de ver nada :laugh:.

Quizás pueda comenzar a quitar las composiciones más externas para dar una idea de lo que es la función g:

Código: [Seleccionar]
g a b = b ( head ( map (\(_,c) -> menor a c).filter (even.fst) ) )
Es decir que g va a ser equivalente a la función b aplicada a 1 parámetro. O sea que podemos decir por el momento que:

Código: [Seleccionar]
g :: ( ... -> z) -> ... -> z
Si pueden indicarme si hasta aquí es correcto y proponer los siguientes pasos (bien detallados), se los agradecería.

Gracias!!
Saludos

26 Mayo, 2021, 03:29 pm
Respuesta #1

geómetracat

  • Moderador Global
  • Mensajes: 4,065
  • País: es
  • Karma: +0/-0
  • Sexo: Masculino
Creo este espacio con la intención de que sea colaborativo y abierto para todo aquel que sepa programar en Haskell, un lenguaje que se basa bastante en las matemáticas que todos conocemos, con sus particularidades.

En realidad Haskell es teoría de categorías camuflada como lenguaje de programación.  ;D

Veamos, lo que tienes aquí es una función \[ g \] que toma dos parámetros \[ a,b \] y te devuelve una función que está definida como composición de otras cuatro. Quizás se vea más claro si se introducen paréntesis y se escribe así:

Código: [Seleccionar]
g a b = b.head.(map (\(_,c) -> menor a c)).(filter (even.fst))
Como \( \text{g a b} \) es una función, para encontrar su tipo debes aplicarla a un elemento (digamos \[ d \], de tipo \[ t(d) \]) y encontrar el tipo de \[ \text{(g a b) d} \]. Si este último tipo es \[ u \], tendrás que \[ \text{g a b} \] tiene tipo \[ t(d) \to u \] y por tanto \[ g \] tendrá tipo \[ t(a) \to t(b) \to t(d) \to u \].

Por tanto, vamos a intentar inferir el tipo de:
Código: [Seleccionar]
(g a b) d = b ( head ( (map (\(_,c) -> menor a c) (filter (even.fst) d))))
Ahora lo más natural es ir de dentro hacia fuera. La primera observación es que \[ d \] debe tener tipo \[ t(d)=[(x,y)] \] donde \[ x,y \] son otros tipos. Esto es por un lado por el tipo de filter, que es de tipo \[ (a \to Bool) \to [a] \to [a]  \] y porque \[ even.fst \] es de tipo \[ (x,y) \to Bool \] (ya que \[ fst \] es de tipo \[ (x,y) \to x \] y \[ even \] de tipo \[ x \to Bool \]). Además, puedes deducir que \[ x \] debe ser un tipo de números enteros (para que la aplicación de \[ even \] tenga sentido). Por otro lado, conociendo el tipo de filter se ve que el tipo de
Código: [Seleccionar]
filter (even.fst) d es de nuevo \[ [(x,y)] \].


También está bien a la vez que miras el tipo ir entendiendo qué hace la función, lo cual te será de ayuda para localizar errores. En este primer paso, tenemos que \[ d \] es una lista de tuplas (donde los elementos de la primera componente son enteros) y
Código: [Seleccionar]
filter (even.fst) dnos devuelve otra lista con las tuplas cuya primera componente es par.

Si quieres puedes ir siguiendo tú. Si tienes algún problema dilo y pongo una solución completa. Una observación por eso es que el tipo depende de la función \[ menor \], que no es una función estándar de Haskell y debe estar definida aparte. Imagino que la intención es que sea algo como \[ menor :: Int \to Int \to Bool \], donde aplicado a dos enteros devuelve True si el primero es menor que el segundo y False en caso contrario.

Agregado.
La ecuación más bonita de las matemáticas: \( d^2=0 \)

28 Mayo, 2021, 08:32 am
Respuesta #2

manooooh

  • $$\Large \color{#9c57a6}\pi\,\pi\,\pi\,\pi\,\pi\,\pi$$
  • Mensajes: 4,791
  • País: ar
  • Karma: +1/-0
  • Sexo: Masculino
Hola geómetracat! Qué bueno que sepas de esto, ¿por casualidad tienes un compilador de Haskell instalado en tu ordenador para probar todas estas cosas? Me da curiosidad, aunque quizás sea un juego de niños para ti porque es más matemática que programar.

En realidad Haskell es teoría de categorías camuflada como lenguaje de programación.  ;D

:o sé que cae dentro del paradigma funcional, pero su simpleza inicial me ha cautivado. ¿No crees que Haskell es matemáticas? Porque por ejemplo f x = x es directamente una función (la identidad), donde f x es equivalente a x, en cambio en C por ejemplo no es así.

Con respecto a lo otro lo voy a leer más detenidamente cuando tenga tiempo. Gracias por tu ayuda.

Saludos

28 Mayo, 2021, 09:08 am
Respuesta #3

geómetracat

  • Moderador Global
  • Mensajes: 4,065
  • País: es
  • Karma: +0/-0
  • Sexo: Masculino
Qué bueno que sepas de esto, ¿por casualidad tienes un compilador de Haskell instalado en tu ordenador para probar todas estas cosas?
Sí, tengo un compilador de Haskell instalado. También tengo el ghci (compilador interactivo) que va muy bien para hacer pruebas "en directo", pues vas escribiendo directamente los comandos ahí.

Citar
Me da curiosidad, aunque quizás sea un juego de niños para ti porque es más matemática que programar.
Tampoco te creas. Sé algunas cositas, pero yo no diría que sé programar en Haskell. Desde luego, sé mucho menos que de programar en Python, por ejemplo. He tenido que mirar qué eran varios de los comandos que aparecían aquí.
Por otro lado, aunque está mucho más cerca de las matemáticas que la programación imperativa, la programación funcional no deja de ser programación.

Citar
:o sé que cae dentro del paradigma funcional, pero su simpleza inicial me ha cautivado. ¿No crees que Haskell es matemáticas? Porque por ejemplo f x = x es directamente una función (la identidad), donde f x es equivalente a x, en cambio en C por ejemplo no es así.
Tiene mucho que ver con matemáticas, claro. Precisamente la teoría de categorías es una rama de las matemáticas que trata básicamente de "aplicaciones" entre objetos (aquí tipos) que se pueden componer. Haskell está muy basado en eso, y de hecho hay muchas ideas y construcciones de teoría de categorías que tienen su contrapartida en Haskell.

[quote
Con respecto a lo otro lo voy a leer más detenidamente cuando tenga tiempo. Gracias por tu ayuda.
[/quote]

Cuando quieras lo comentamos.
La ecuación más bonita de las matemáticas: \( d^2=0 \)

28 Mayo, 2021, 09:23 am
Respuesta #4

manooooh

  • $$\Large \color{#9c57a6}\pi\,\pi\,\pi\,\pi\,\pi\,\pi$$
  • Mensajes: 4,791
  • País: ar
  • Karma: +1/-0
  • Sexo: Masculino
Hola

Sí, tengo un compilador de Haskell instalado. También tengo el ghci (compilador interactivo) que va muy bien para hacer pruebas "en directo", pues vas escribiendo directamente los comandos ahí.

Ah, sí, con el Prelude y tal. :) Yo también lo uso, mi IDE es el VS Code. ¿Cuál es el tuyo?

Tampoco te creas. Sé algunas cositas, pero yo no diría que sé programar en Haskell. Desde luego, sé mucho menos que de programar en Python, por ejemplo. He tenido que mirar qué eran varios de los comandos que aparecían aquí.
Por otro lado, aunque está mucho más cerca de las matemáticas que la programación imperativa, la programación funcional no deja de ser programación.

¿Eres fanático de usar composición (.)  y notación point-free? Porque me cuesta horrores tratar de usarlos cuando hay funciones de más de 2 parámetros :laugh:.

Tiene mucho que ver con matemáticas, claro. Precisamente la teoría de categorías es una rama de las matemáticas que trata básicamente de "aplicaciones" entre objetos (aquí tipos) que se pueden componer. Haskell está muy basado en eso, y de hecho hay muchas ideas y construcciones de teoría de categorías que tienen su contrapartida en Haskell.

Claro, sobretodo me recuerda cuando trabajamos con tuplas. El caso de que sean 2 componentes es un par ordenado, tal como trabajamos en matemáticas.

Por cierto, una curiosidad que preguntando me dijeron que no se puede: ¿Sabes si luego de agregar al principio del código la línea "import Text.Show.Functions" se puede mostrar el nombre una función? Por ejemplo al importarlo y hacer una consulta dice:

Código: [Seleccionar]
> [id, map (*2)]
[<function>,<function>]

Quería saber si en realidad se puede mostrar algo como:

Código: [Seleccionar]
> [id, map (*2)]
[id,map (*2)]

o

Código: [Seleccionar]
> [id, map (*2)]
["id","map (*2)"]

pero no [<function>,<function>]. Esto es porque estaba haciendo un trabajo práctico, y cuando hice el modelado de un ejercicio necesitaba (según lo que planteé) mostrar por consola una función de acceso de un data, entonces no podía trabajar con eso porque siempre me aparecía <function> y no me da información relevante para lo que necesitaba :laugh:. Quizás haya alguna forma tricky, pero no sé.

Saludos

28 Mayo, 2021, 11:40 am
Respuesta #5

geómetracat

  • Moderador Global
  • Mensajes: 4,065
  • País: es
  • Karma: +0/-0
  • Sexo: Masculino
Ah, sí, con el Prelude y tal. :) Yo también lo uso, mi IDE es el VS Code. ¿Cuál es el tuyo?

Cuando hago algo de esto suelo usar emacs (en Linux).

Citar
¿Eres fanático de usar composición (.)  y notación point-free? Porque me cuesta horrores tratar de usarlos cuando hay funciones de más de 2 parámetros :laugh:.
Hombre, es más elegante, y ayuda a pensar en términos de funciones (como debe ser) y no tanto en términos imperativos.
Por otra parte, las funciones de dos argumentos (o más) no existen en Haskell estrictamente hablando, solamente las de un argumento. Todas las funciones están currificadas (es decir, en vez de funciones \[ A\times B \to C \] tienes las funciones equivalentes \[ A \to B \to C \]). Lo que pasa entonces es que una función aplicada a un argumento da otra función, que puedes aplicar a otro argumento, etc.

Citar
Por cierto, una curiosidad que preguntando me dijeron que no se puede: ¿Sabes si luego de agregar al principio del código la línea "import Text.Show.Functions" se puede mostrar el nombre una función? Por ejemplo al importarlo y hacer una consulta dice:

Código: [Seleccionar]
> [id, map (*2)]
[<function>,<function>]

Quería saber si en realidad se puede mostrar algo como:

Código: [Seleccionar]
> [id, map (*2)]
[id,map (*2)]

o

Código: [Seleccionar]
> [id, map (*2)]
["id","map (*2)"]

pero no [<function>,<function>]. Esto es porque estaba haciendo un trabajo práctico, y cuando hice el modelado de un ejercicio necesitaba (según lo que planteé) mostrar por consola una función de acceso de un data, entonces no podía trabajar con eso porque siempre me aparecía <function> y no me da información relevante para lo que necesitaba :laugh:. Quizás haya alguna forma tricky, pero no sé.

Pues parece que no. Yo de entrada no tengo ni idea, pero lo he buscado y he visto esto:
    https://stackoverflow.com/questions/43410291/why-does-text-show-functions-only-return-function   
     https://wiki.haskell.org/Show_instance_for_functions 

Si lo entiendo bien, básicamente la idea parece ser que a partir de la manera en que Haskell guarda y representa internamente una función es imposible deducir una expresión para ella.
La ecuación más bonita de las matemáticas: \( d^2=0 \)

28 Mayo, 2021, 03:38 pm
Respuesta #6

Juan Pablo Sancho

  • Moderador Global
  • Mensajes: 6,562
  • País: es
  • Karma: +0/-0
  • Sexo: Masculino

28 Mayo, 2021, 09:16 pm
Respuesta #7

C. Enrique B.

  • $$\Large \color{#c88359}\pi\,\pi\,\pi\,\pi$$
  • Mensajes: 603
  • País: es
  • Karma: +0/-0
    • Mi página en WikiPedia.
-
Muy buen video. Creo que guardé su enlace meses atrás (para revisión posterior), así que te agradezco el aporte.

La fecha YouTube es de hace 6 años.
-
-- FALTAN LAS MUJERES en muchos ámbitos sociales. Yo no me siento perteneciente al bando masculino; soy del bando de las personas. Chicas, manifestáos; no concibo charlar sobre un tema si no estáis vosotras: es impropio, casi absurdo.