variable print functions custom argument typeclass haskell

typeclass - functions - print variable haskell



¿Cuál es el efecto de los sinónimos de tipo en las instancias de las clases de tipo? ¿Qué hace el Pragma TypeSynonymInstances en GHC? (4)

Creo que parte del problema es que hay dos restricciones, en gran parte no relacionadas, que están en juego:

  • No hay instancias de sinónimos de tipo significa que las instancias solo pueden ser cosas declaradas con data o newtype , no con type . Esto prohíbe la String , pero no [Char] .
  • Ninguna instancia flexible significa que las instancias solo pueden mencionar un tipo que no sea una variable, y solo ese tipo se puede usar como un constructor de tipos. Esto prohíbe Maybe Int y f Int , pero no Maybe a .

Esto es lo que dice GHCi sobre Int , Char y String :

data Char = GHC.Types.C# GHC.Prim.Char# data Int = GHC.Types.I# GHC.Prim.Int# type String = [Char]

Int y Char son tipos simples sin parámetros de variable de tipo; no hay ningún tipo de constructor involucrado, así que puedes crear instancias con ellos de manera bastante libre.

Cadena, sin embargo, falla en ambos casos . Es un sinónimo de tipo, que no está permitido, y también es un constructor de tipo aplicado a una no variable , es decir, el constructor de tipo de lista aplicado a Char.

A modo de comparación, tenga en cuenta que [a] , Maybe a , y Either ab son todos válidos en instancias, pero [Int] , Maybe [a] y Either String a están prohibidos; Esperemos que ahora puedas ver por qué.

En cuanto a sus preguntas directas, no sé cuáles fueron las motivaciones originales para diseñar el lenguaje de esa manera, y de ninguna manera estoy calificado para hacer declaraciones autorizadas sobre "mejores prácticas", pero no conozco mi propia codificación personal. Realmente dudo en usar estos pragmas:

{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE EmptyDataDecls #-} {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleContexts #-}

Siempre puedes ir a buscar paquetes que usen pragmas . Al parecer, las instancias flexibles obtienen una buena cantidad de uso, y de paquetes "respetables" (hay un par de hits en la fuente de Parsec, por ejemplo).

Estoy leyendo Real World Haskell Pg 151, y he mirado el siguiente pasaje durante más de una hora:

Recuerde que String es un sinónimo de [Char], que a su vez es del tipo [a] donde Char se sustituye por el parámetro de tipo a. De acuerdo con las reglas de Haskell 98, no se nos permite suministrar un tipo en lugar de un parámetro de tipo cuando escribimos una instancia. En otras palabras, sería legal para nosotros escribir una instancia para [a], pero no para [Char]. 16 comentarios 5335

Simplemente no se está hundiendo. Mirando la copia (gratuita y no pirateada) del capítulo 6 de RWH , veo que muchas otras personas realmente están sufriendo con esto. Todavía no lo entiendo por los comentarios ...

En primer lugar, todo lo relacionado con esto me confunde, así que, por favor, si cree que puede explicar algo sobre este pasaje, o TypeSynonymInstances por favor.

Aquí está mi problema:

  • Int es un constructor de datos
  • String es un constructor de datos y un sinónimo de tipo

Ahora no puedo responder estas preguntas:

  1. ¿Por qué un sinónimo de tipo excluiría hacer que el tipo sea un miembro de una clase de tipo (estoy buscando alguna razón que probablemente esté relacionada con la compilación o la implementación de un sinónimo de tipo)?
  2. ¿Por qué los diseñadores del lenguaje no querían esta sintaxis (pido razonamiento, no teoría extensa o símbolos matemáticos de Unicode)?
  3. Veo esta línea "el tipo [a] donde Char se sustituye por el parámetro de tipo a" , y quiero saber por qué no puedo sustituirlo por este "the type a donde Int se sustituye por el parámetro de tipo a" .

¡Gracias!


En realidad, ni Int ni String son constructores de datos. Es decir, no puedes usarlos para crear un valor de

> (Int 42, String "bob") <interactive>:1:1: Not in scope: data constructor `Int'' <interactive>:1:9: Not in scope: data constructor `String''

Int nombra un tipo de datos algebraico nuevo y distinto. String es un "sinónimo de tipo", o alias, para el tipo ya existente: [Char] . El problema es que Haskell 98 dice que no puede usar un sinónimo de tipo en una declaración de instancia.

No puedo decir por qué los autores del informe Haskell 98 optan por restringir los sinónimos de tipo en este caso. Hay un buen número de restricciones en ellos. Por ejemplo, no se pueden aplicar parcialmente (si toman argumentos de tipo). Creo que una pista viene al final de §4.2.2:

Los sinónimos de tipo son un mecanismo conveniente, pero estrictamente sintáctico, para hacer que las firmas de tipo sean más legibles. Un sinónimo y su definición son completamente intercambiables, excepto en el tipo de instancia de una declaración de instancia (Sección 4.3.2).

Presumiblemente, hubo un enfoque para la compilación del programa, por lo que esta capacidad de intercambio sintáctico habría causado problemas para los casos. Tal vez tenga que ver con aspectos notables de los casos en que se escapan de paquetes ...

En cuanto a su última pregunta, creo que la explicación está combinando dos cosas: 1) La String es un sinónimo de tipo para [Char] , que a su vez es una especialización del tipo más general [a] y 2) que incluso sin el sinónimo, [Char] no se puede utilizar en el encabezado de una instancia.

Este segundo problema no tiene nada que ver con los sinónimos de tipo, pero los jefes de instancia deben tener todos los parámetros de tipo para que el constructor de tipos sean variables, no tipos concretos. Es decir, no puede definir instancias separadas para [Int] y [Char] para alguna clase, solo puede definir instancias [a] . (Recuerde que, a pesar de la práctica sintaxis, [] es un constructor de tipo, y la cosa que está dentro es el parámetro de tipo).

Nuevamente, no sé por qué el informe restringe esto, pero sospecho que también tiene que ver con la estrategia de compilación. Dado que la estrategia de compilación de GHC para instancias puede manejar esto, puede relajar esta restricción en GHC a través de -XFlexibleInstances .

Finalmente, he visto ambas extensiones activadas en bastante código, pero tal vez alguien con más experiencia en Haskell pueda opinar sobre si son "mejores prácticas" o no.


Int y String son tipos, no constructores de datos. La cadena pasa a ser un alias para [Char] que también se puede escribir List Char. Un constructor de datos es algo como Just, por lo que Just 3 es un valor del tipo Maybe Int. Las instancias de sinónimos de tipo se explican aquí:

TypeSynonymInstances


Haskell 98

  1. un encabezado de instancia debe tener la forma C (T u1 ... uk), donde T es un constructor de tipo definido por una declaración de datos o newtype (ver TypeSynonymInstances ) y la ui son variables de tipo distintas, y
  2. Cada aserción en el contexto debe tener la forma C ''v, donde v es una de las ui.

Por lo tanto, es válido usar la instance ClassName TypeConstructor where y TypeConstructor DEBE ser como Int , Double o [a] , ¡asegúrese de que solo pueda participar un constructor de tipos!

Por cierto, [] es un constructor de tipo, por lo que no se puede usar [TypeVariable] se permiten [NewType] y [TypeVariable] .

Esta es una restricción es Haskell, y podemos evitarla habilitando FlexibleInstances .