Saltar al contenido

tipos y variable de tipo en Haskell

Te damos la bienvenida a nuestra página, en este lugar encontrarás la resolución que estás buscando.

Solución:

Cuando decimos eso e :: [a], esto significa que e es una lista de elementos de cualquier tipo. ¿Que tipo? ¡Cualquier tipo! Cualquiera que sea el tipo que necesite en este momento.

Si viene de un lenguaje que no es ML, esto podría ser un poco más fácil de entender si mira primero una función (en lugar de un valor). Considera esto:

f x = [x]

El tipo de esta función es f :: a -> [a]. Esto significa, aproximadamente, que esta función funciona para cualquier tipo a. Le das un valor de este tipo, y te devolverá una lista con elementos de ese tipo. ¿Que tipo? ¡Cualquier tipo! Lo que sea que necesites.

Cuando llamo a esta función, efectivamente escoger qué tipo quiero en este momento. Si lo llamo como f 'x', Yo elijo a = Char, y si lo llamo como f True, Yo elijo a = Bool. Entonces, el punto importante aquí es que quien llama a una función elige el parámetro de tipo.

Pero no tengo que elegirlo una sola vez y para toda la eternidad. En su lugar, elijo el parámetro de tipo cada vez que llamo a la función. Considera esto:

pair = (f 'x', f True)

Aquí estoy llamando f dos veces, y elijo diferentes parámetros de tipo cada vez, la primera vez que elijo a = Chary la segunda vez elijo a = Bool.

Bien, ahora para el siguiente paso: cuando elijo el parámetro de tipo, puedo hacerlo de varias maneras. En el ejemplo anterior, lo elijo pasando un parámetro de valor del tipo que quiero. Pero otra forma es especificar el tipo de resultado que quiero. Considera esto:

g x = []

a :: [Int]
a = g 0

b :: [Char]
b = g 42

Aquí, la función g ignora su parámetro, por lo que no hay relación entre su tipo y el resultado de g. Pero todavía puedo elegir el tipo de ese resultado al tenerlo limitado por el contexto circundante.

Y ahora, el salto mental: una función sin parámetros (también conocida como “valor”) no es tan diferente de una función con parámetros. Simplemente tiene cero parámetros, eso es todo.

Si un valor tiene parámetros de tipo (como su valor e por ejemplo), puedo elegir ese parámetro de tipo cada vez que “llamo” a ese valor, con la misma facilidad que si fuera una función. Entonces en la expresión e == ec && e == en simplemente estás “llamando” el valor e dos veces, eligiendo diferentes parámetros de tipo en cada llamada, al igual que he hecho en el pair ejemplo anterior.


La confusión sobre Num es un asunto completamente diferente.

Verás, Num no es un tipo. Es un clase de tipo. Las clases de tipos son una especie de interfaces en Java o C #, excepto que puede declararlas más tarde, no necesariamente junto con el tipo que los implementa.

Entonces la firma en :: Num a => [a] significa que en es una lista con elementos de alguna tipo, siempre que ese tipo implemente (“tiene una instancia de”) la clase de tipo Num.

Y la forma en que funciona la inferencia de tipos en Haskell es que el compilador primero determinará los tipos más concretos que pueda y luego tratará de encontrar implementaciones (“instancias”) de las clases de tipos requeridas para esos tipos.

En su caso, el compilador ve que en :: [a] está siendo comparado con ec :: [Char]y figura: “Oh, lo sé: a debe ser Char! “Y luego va a buscar las instancias de clase y se da cuenta de que a debe tener una instancia de Num, y desde a es Char, resulta que Char debe tener una instancia de Num. Pero no es así, por lo que el compilador se queja: “no se puede encontrar (Num Char)”

En cuanto a “derivado del uso de en“- bueno, eso es porque en es la razón por la que un Num Se requiere instancia. en es el que tiene Num en su firma de tipo, por lo que su presencia es lo que provoca el requisito de Num

A veces, es conveniente pensar en las funciones polimórficas como funciones que toman explícitamente escribir argumentos. Consideremos la función de identidad polimórfica como ejemplo.

id :: forall a . a -> a
id x = x

Podemos pensar en esta función de la siguiente manera:

  • primero, la función toma como entrada un argumento de tipo llamado a
  • segundo, la función toma como entrada un valor x del tipo previamente elegido a
  • por último, la función regresa x (de tipo a)

Aquí hay una posible llamada:

id @Bool True

Sobre el @Bool pasa de sintaxis Bool para el primer argumento (tipo argumento a), tiempo True se pasa como segundo argumento (x de tipo a = Bool).

Algunos otros:

id @Int 42
id @String "hello"
id @(Int, Bool) (3, True)

Incluso podemos aplicar parcialmente id pasando solo el argumento de tipo:

id @Int       :: Int -> Int
id @String    :: String -> String
...

Ahora, tenga en cuenta que en la mayoría de los casos Haskell nos permite omitir el argumento de tipo. Es decir, podemos escribir id "hello" y GHC intentará inferir el argumento de tipo que falta. Aproximadamente funciona de la siguiente manera: id "hello" se transforma en id @t "hello" para algún tipo desconocido t, luego según el tipo de id esta llamada solo puede escribir check si "hello" :: t, y desde "hello" :: String, podemos inferir t = String.

La inferencia de tipos es extremadamente común en Haskell. Los programadores rara vez especifican sus argumentos de tipo y dejan que GHC haga su trabajo.

En tu caso:

e :: forall a . [a]
e = []
ec :: [Char]
ec = tail "1"
en :: [Int]
en = tail [1]

Variable e está vinculado a un valor polimórfico. Es decir, en realidad es una especie de función que toma un argumento de tipo a (que también se puede omitir) y devuelve una lista de tipo [a].

En lugar de, ec no acepta ningún tipo de argumento. Es una lista simple de tipos [Char]. Similarmente para en.

Entonces podemos usar

ec == (e @Char)    -- both of type [Char]
en == (e @Int)     -- both of type [Int]

O podemos dejar que el motor de inferencia de tipos determine los argumentos de tipo implícitos

ec == e     -- @Char inferred
en == e     -- @Int inferred

Esto último puede inducir a error, ya que parece que ec,e,en debe tener el mismo tipo. De hecho, no es así, ya que se están infiriendo diferentes argumentos de tipo implícito.

Si tienes algún recelo o capacidad de arreglar nuestro tutorial puedes dejar una reseña y con deseo lo interpretaremos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *