2009-08-29 10 views
10

Estoy tratando de ampliar mi mente aprendiendo Haskell.¿Cómo funciona Type Deduction en Haskell?

mi tarea autoinfligidas era construir un generador de reloj-tick, que me daría intervalos de distribución de Poisson, y el resultado final (después de una larga lucha, lo admito) fue la siguiente:

import System.Random 
poissonStream :: (Ord r, Random r, Floating r, RandomGen g) => r -> r -> r -> g -> [r] 
poissonStream rate start limit gen 
     | next > limit = [] 
     | otherwise  = next:(poissonStream rate next limit newGen) 
     where (rvalue, newGen) = random gen 
       next = start - log(rvalue)/rate 

Pero Hay dos cosas (al menos) que no entiendo:

¿Por qué necesito "Ord r" y "Floating r"? (Hubiera esperado algún tipo de herencia automática: "Flotante" implica "Ord").

¿Por qué ruta se obtiene la definición de tipo implícita "rvalue :: Float"? En GHCi consigo lo que habría esperado:

*Main System.Random> let (rvalue, newGen) = random (mkStdGen 100) 
<interactive>:1:23: 
    Ambiguous type variable `t' in the constraint: 
     `Random t' arising from a use of `random' at <interactive>:1:23-43 
    Probable fix: add a type signature that fixes these type variable(s) 

rvalue es un cañón suelto que tengo que atar:

*Main System.Random> let (rvalue, newGen) = random (mkStdGen 100) :: (Float, StdGen) 
*Main System.Random> rvalue 
0.18520793 

favor ser suave con un n00b Haskell.

+2

En mi humilde opinión, si esto solo es autoaprendizaje, no lo etiquetaría como tarea. Las preguntas sobre la tarea implican un problema altamente artificial y, en general, cambiarán el tipo de respuesta que obtenga (más que una sugerencia que la de presentarla), a menos que eso sea lo que usted prefiera. – cletus

+0

@cletus: Gracias por la observación. Pensé que era mejor señalar esto como un ejercicio, en lugar de un problema del mundo real, desde el principio. –

+2

Lo etiquetaría como "hobby" o "autoaprendizaje" en lugar de "tarea". La "tarea" no implica "no el mundo real" sino "realmente no me da una respuesta". – Chuck

Respuesta

12

¿Por qué necesito "Ord r" y "Floating r"? (Lo que habría esperado algún tipo de herencia automática: "flotante" implica "Ord".)

Floating se supone que clasificar todos los números de punto flotante, incluyendo los complejos. No hay pedidos para números complejos. Puede usar RealFloat en lugar de Floating, lo que implica Ord.

¿En qué camino se logra la definición implícita del tipo "rvalue :: Float" logrado?

Bueno, puede inferir eso del contexto en el que se usa rvalue. Es el argumento de log y

:t log 

da

log :: (Floating a) => a -> a 

por lo rvalue debe estar en la clase Floating (por lo que será "un cierto tipo en el Floating clase de tipos, no precisamente Float). Además, el resultado de log es del mismo tipo que su entrada y se utiliza en un cálculo con start y rate y se compara con limit que son todos de tipo r, por lo que rvalue será de r (que es adecuado porque r es de Floating también).

En su ejemplo de GHCi, no hay más contexto.Tipo

:t random (mkStdGen 100) 

Esto le da

random (mkStdGen 100) :: (Random a) => (a, StdGen) 

GHCi no sabe qué tipo para reemplazar a a aquí. Solo sabe que debe estar en la clase de tipos Random.

+1

Sí, por supuesto. No se me había ocurrido que Flotante podría incluir flotadores complejos; y gracias por el puntero RealFloat. I * did * entiendo el comportamiento en GHCi; Solo estaba usando eso para contrastar con el comportamiento aparentemente más liberal de mi función. Muchas gracias por una respuesta clara. –

2

En Haskell, Ord y Flotante son conceptos independientes o orthogonal. Tal vez estabas asumiendo que Floating solo se refería a tipos muy específicos, como Double y Float (este sería el caso en la mayoría de los otros idiomas)?

Como señaló Rudiger, hay tipos que son instancias de la clase Flotante que no son Ord porque no hay orden para ciertos tipos de flotación, como Complejo. Otro ejemplo además de los números complejos serían los vectores, para los cuales usted puede definir estas funciones flotantes, pero no cualquier tipo de ordenamiento sensible.

Recuerde que las clases de tipo acaba de especificar el conjunto de funciones (como una interfaz en Java o C#, si eso es una forma útil de pensar en ello) que debe ser definido para un tipo un; ser Ord, un tipo a solo necesita operadores de comparación, y para ser una instancia de Floating, un tipo a solo necesita implementar Fractional y tener las funciones pi, exp, sqrt, log, sin, cos, .. . definido para ellos. Eso es todo flotante, nada más, nada menos.

+0

Gracias. Sí, aprecio el concepto de ortogonalidad; Solo lo estaba aplicando a un espacio conceptual demasiado pequeño. –

Cuestiones relacionadas