tuplas tipos sobre opciones multiplos multiplicar hacer funciones ejemplos como clases basico haskell types

tipos - Haskell, multiplicando Int y Float dentro de una función



multiplicar haskell (4)

Intente lo siguiente en su lugar:

test :: Float -> Int -> Int -> Float test a b c = a * fromIntegral (b - c)

¿Por qué funciona esto?

  1. Como b y c son ambos Int s, la expresión (b - c) también es un Int .
  2. La firma de tipo de (*) es Num a => a -> a -> a .
  3. Debido a que a es de tipo Float Haskell actualiza la firma de tipo de (a*) a Float -> Float .
  4. Sin embargo, dado que (b - c) es un Int y no un Float Haskell se quejaría si intentara hacer a * (b - c) .
  5. La firma de tipo de fromIntegral es (Integral a, Num b) => a -> b .
  6. Por lo tanto, la firma de tipo de fromIntegral (b - c) es Num b => b .
  7. Ya que Float es una instancia de Typeclass Num se le permite hacer a * fromIntegral (b - c) porque la firma de tipo de (*) es Num a => a -> a -> a .
  8. El resultado, a partir de la firma de tipo de test evalúa como Float .

Espero que esto haya ayudado.

¿Por qué es que en ghci puedo entrar?

5.0 * (3 - 1) > 10.0

Pero si intento crear una función en un archivo .hs y la cargo en:

test :: Float -> Int -> Int -> Float test a b c = a * (b - c)

Estoy golpeado con un error? "¿No podría coincidir el tipo esperado ''Flotante'' con el tipo inferido ''Int''? ¿Y cómo puedo escribir una función que tome un punto flotante y 2 argumentos enteros y realice la operación anterior en ellos?

Estoy usando ghci v6.12.1 si eso hace una diferencia ...


Los literales numéricos (es decir, solo escribir un número en el código de Haskell) no son un tipo fijo. Son polimórficos. Deben ser evaluados en algún contexto que requiere que tengan un tipo concreto.

Así que la expresión 5.0 * (3 - 1) no está multiplicando un Int por un Float . 5.0 tiene que ser algún tipo Fractional , 3 y 1 son cada uno tipo Num . 3 - 1 significa que tanto el 3 como el 1 tienen que ser del mismo tipo Num , pero aún no tenemos (aún) más restricciones acerca de cuál particular es; El resultado de la resta es el mismo tipo.

El * significa que ambos argumentos deben ser del mismo tipo, y el resultado también será el mismo tipo. Como 5.0 es un tipo Fractional , el (3 - 1) debe serlo. Ya sabíamos que 3 , 1 y (3 - 1) tenían que ser algún tipo Num pero todos los tipos Fractional también son tipos Num , por lo que estos requisitos no están en conflicto.

El resultado final es que toda la expresión 5.0 * (3 - 1) es un tipo que es Fractional , y que el 5.0 , 3 y 1 son todos del mismo tipo. Puede usar el comando :t en GHCi para ver esto:

Prelude> :t 5.0 * (3 - 1) 5.0 * (3 - 1) :: Fractional a => a

Pero para evaluar realmente esa expresión, necesitamos hacerlo para algún tipo concreto. Si estuviéramos evaluando esto y pasándolo a alguna función que requiera Float , Double , o algún otro tipo Fractional particular, Haskell lo escogería. Si solo evaluamos la expresión sin ningún otro contexto que requiera que sea un tipo particular, Haskell tiene algunas reglas predeterminadas para elegir automáticamente una (si las reglas predeterminadas no se aplican, en su lugar le dará un error de tipo sobre las variables de tipo ambiguo ).

Prelude> 5.0 * (3 - 1) 10.0 Prelude> :t it it :: Double

Anteriormente, he evaluado 5.0 * (3 - 1) , luego le pregunté por el tipo de variable mágica que GHCi siempre vincula al último valor que evaluó. Esto me dice que GHCi ha predeterminado mi tipo Fractional a => a a Double solo para calcular que el valor de la expresión era 10.0 . Al hacer esa evaluación, solo multiplicó (y restó) el Double s, nunca multiplicó un Double por un Int .

Ahora, eso es lo que sucede cuando intentas múltiples literales numéricos que parecen ser de diferentes tipos. Pero su función de test no es multiplicar los literales, es multiplicar variables de tipos conocidos particulares. En Haskell no puede multiplicar un Int por un Float porque el operador * tiene el tipo Num a => a -> a -> a - toma dos valores del mismo tipo numérico y le da un resultado que es ese tipo. Puede multiplicar un Int por un Int para obtener un Int , o un Float por un Float para obtener un Float . No puedes multiplicar un Int por un Float para obtener un ??? .

Otros idiomas admiten este tipo de operación solo mediante la inserción implícita de llamadas a funciones de conversión bajo ciertas circunstancias. Haskell nunca convierte implícitamente entre tipos, pero tiene las funciones de conversión. Solo necesita llamarlos explícitamente si desea que se los llame. Esto haría el truco:

test :: Float -> Int -> Int -> Float test a b c = a * fromIntegral (b - c)


Su función de test fue más general, antes de agregar una firma:

> let test a b c = a * (b - c) > :t test test :: Num a => a -> a -> a -> a

Podrías restringirlo, pero todos los tipos deben ser iguales:

test :: Fractional a => a -> a -> a -> a -- some real types test :: Integral a => a -> a -> a -> a -- all integer types test :: Float -> Float -> Float -> Float test :: Int -> Int -> Int -> Int test :: Int -> Float -> Float -> Float --wrong

Por cierto, 2 no es Int y 0.2 no es Float , vamos a preguntar gchi :

> :t 2 2 :: Num a => a > :t 0.2 0.2 :: Fractional a => a


fromIntegral utilizar fromIntegral en los enteros antes de multiplicar por los flotantes.

http://www.haskell.org/haskellwiki/Converting_numbers

En GHCI, no se asume que los números sean flotantes o ints hasta que los uses. (por ejemplo: en tiempo de ejecución). Eso funciona mejor para el desarrollo de estilo REPL.

En el compilador propiamente dicho, no hay ninguna coacción automática. Se ve que la multiplicación supone que los dos valores deben pertenecer a una clase de tipos que admita la multiplicación. Por ejemplo: multiplicar entradas, o multiplicar flotantes. Como no usó ninguna otra función explícitamente escrita, asumió ints. Esa suposición luego difiere con su firma de tipo (opcional).