recursivos - potencia en haskell
¿Por qué no escribir sinónimos permite la recursión en Haskell? (2)
Esto tiene que ver con los tipos equi recursivos frente a los tipos isocurrentes . Haskell implementa tipos recursivos usando tipos isorecitativos, que requieren que el programador le diga al verificador de tipos cuando está ocurriendo una recursión de tipo. La forma en que lo marcas es con un constructor específico, que un simple tipo-sinónimo no te permite tener.
Los tipos recursivos equitativos permiten al compilador inferir dónde ocurre la recursión, pero conduce a un verificador de tipos mucho más complicado y, en algunos casos aparentemente simples, el problema es indecidible.
Si desea una buena discusión de los tipos recursivo equi vs. iso, consulte los excelentes tipos y lenguajes de programación de Benjamin Pierce.
Respuesta corta: como los sinónimos de tipo no introducen constructores, y haskell necesita constructores para marcar explícitamente la recursión en el nivel de tipo, no puede usar sinónimos de tipo recursivo.
¿Alguien puede explicar por qué estos compilan alegremente?
data A a b = A { a :: a, b :: b }
newtype B a = B (A a (B a))
newtype C = C (A Int C)
¿Pero no puedo crear tipos similarmente recursivamente definidos a través de sinónimos de tipo?
type B a = A a (B a)
type C = A Int C
Aunque obviamente los data B a = A { a :: a, b :: B a }
funcionan bien.
¿Hay alguna manera de evitar tratar con ese constructor adicional X donde quiera que el tipo sea recursivo? En su mayoría, paso funciones de acceso que seleccionan el b
todos modos, así que estoy más que bien, pero si existe un mecanismo de elusión fácil, me gustaría saberlo.
¿Algún pragma que debería utilizar para mejorar el rendimiento con el tipo de datos especializado C? Solo especializo cosas?
¿Algún truco ingenioso para copiar entre A ab
y A cd
definiendo solo el mapeo a a -> b
y c -> d
sin copiar sobre el registro dos veces? Me temo que los campos de A cambiarán en el futuro. ¿Plantilla Haskell quizás?
Responderé tu primera pregunta y segunda pregunta.
El tipo de B es el tipo infinito (A a (A a (A a (A a (...)))))
El "motor de inferencia de tipo" podría diseñarse para inferir y manejar tipos infinitos. Desafortunadamente, muchos errores (tipográficos o lógicos) del programador crean código que no tiene el tipo finito deseado y accidentalmente e inesperadamente tiene un tipo infinito. En este momento el compilador rechaza dicho código, que es casi siempre lo que el programador quiere. Cambiarlo para permitir tipos infinitos crearía errores mucho más difíciles de entender en tiempo de compilación (al menos tan malo como las plantillas de C ++) y en casos excepcionales podría hacer que se compile y funcione incorrectamente en el tiempo de ejecución.
¿Hay alguna manera de evitar tratar con ese constructor adicional X donde quiera que el tipo sea recursivo?
No. Haskell ha elegido permitir tipos recursivos solo con constructores de tipos explícitos a partir de data
o tipo newtype
. Esto hace que el código sea más detallado, pero newtype
debería tener una pequeña penalización de tiempo de ejecución. Es una decisión de diseño.