¿Cuál es el efecto de sinónimos tipos sobre las instancias de clases de tipos? ¿Qué hace el pragma TypeSynonymInstances en GHC?

StackOverflow https://stackoverflow.com/questions/2125674

  •  22-09-2019
  •  | 
  •  

Pregunta

Estoy leyendo Real World Haskell Pg 151, y me ha mirado fijamente en el siguiente pasaje de más de una hora:

  

Hay que recordar que de cuerdas es sinónimo de   [Char], que a su vez es el tipo [a]   donde Char es sustituido por el tipo de   parámetro a. Según Haskell 98 de   reglas, no se les permite suministrar una   escriba en lugar de un parámetro de tipo cuando   escribimos una instancia. En otras palabras,   sería legal para que escribamos una   instancia para [a], pero no para [Char].   16 comentarios 5335

Se trata simplemente de no hundirse en. Fijamente en el href="http://book.realworldhaskell.org/read/using-typeclasses.html" rel="noreferrer"> la copia veo mucho de otras personas realmente sufren con esto. Todavía no entiendo de los comentarios ...

En primer lugar, todo lo relacionado Esto confunde a mí, así que por favor, si usted siente que puede explicar nada sobre este pasaje, o TypeSynonymInstances por favor.

Aquí está mi problema:

  • Int es un los datos del constructor
  • String es un datos constructor y tipo de sinónimos

Ahora no puedo responder a estas preguntas:

  1. ¿Por qué un sinónimo de tipo excluye la fabricación del tipo de un miembro de una clase de tipo (estoy mirando por alguna razón, que probablemente se relaciona con la compilación o implimentation de un sinónimo de tipo)?
  2. ¿Por qué los diseñadores de la lengua, no quiero esta sintaxis (que estoy pidiendo razonamiento no extensa teoría o símbolos matemáticos Unicode).
  3. Veo esta línea "del tipo [a] donde Char es sustituido por el tipo de parámetro a" , y quiero saber por qué no puedo sustituirlo por este "la tipo a donde Int es sustituido por el tipo de parámetro de un ".

Gracias!

¿Fue útil?

Solución

Creo que parte del problema es que dos, en gran parte sin relación, las restricciones están en juego:

  • No Tipo de sinónimos casos los medios que los casos sólo puede ser declarada con cosas data o newtype, no type. Este prohíbe String, pero no [Char].
  • No hay instancias medios flexibles que los casos sólo se pueden mencionar un tipo que no es una variable, y sólo ese tipo puede ser utilizado como un constructor de tipos. Esto prohíbe Maybe Int y f Int, pero no Maybe a.

Esto es lo que dice acerca GHCi 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 ambos tipos simples sin parámetros de tipo de variable; no hay constructor de tipos involucrados, por lo que puede crear instancias con ellos más o menos libremente.

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

A modo de comparación, cabe destacar que [a], Maybe a y Either a b son todas válidas en los casos, pero [Int], Maybe [a] y Either String a están prohibidas; esperamos que ahora puede ver por qué.

En cuanto a sus preguntas directas, no sé cuáles son las motivaciones originales eran para el diseño de la lengua de esa manera, y yo soy de ninguna manera calificado para hacer declaraciones sobre autorizada "mejores prácticas", pero por mi propio código personal realmente no me atrevo a usar estos pragmas:

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

Siempre se puede ir a buscar a los paquetes que pragmas uso . instancias flexibles, al parecer, consiguen una buena cantidad de uso, y de paquetes de "respetables" (hay un par de hits en la fuente de Parsec, por ejemplo).

Otros consejos

En realidad, ni tampoco Int String son constructores de datos. Es decir, no se puede utilizar 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'

nombres Int una nueva, distinta, algebraica de tipos de datos. String es un "tipo-sinónimo", o alias, para el tipo ya existente: [Char]. El problema es que Haskell 98 dice que no se puede utilizar un sinónimo de tipo en una declaración de la instancia.

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

  

Sinónimos de tipo son una conveniente, pero   estrictamente sintáctica, el mecanismo para hacer   las firmas de tipos más legible. UNA   sinónimo y su definición son   completamente intercambiables, excepto en   el tipo de instancia de una instancia   declaración (Sección 4.3.2).

Es de suponer que hubo un acercamiento a la compilación del programa, para lo cual habría provocado esta intercambiabilidad sintáctica problemas para las instancias. Tal vez tiene que ver con el aspecto notable de los casos que se producen pérdidas de paquetes ...

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

Este segundo problema no tiene nada que ver con los sinónimos tipo, pero que las cabezas de instancia debe tener todos los parámetros de tipo para el constructor de tipos variables, puede no tipos concretos. Es decir, no se puede definir instancias separadas para [Int] y [Char] por alguna clase, sólo se puede definido un [a] casos. (Recuerde, que a pesar de la sintaxis conveniente, [] es un constructor de tipos, y lo interior es el parámetro de tipo.)

Una vez más, no sé por qué el informe que los limita, pero sospecho que también tiene que ver con la estrategia de compilación. Dado que la estrategia de recopilación de GHC para casos puede manejar esto, se puede relajar esta restricción en GHC través -XFlexibleInstances.

Por último, he visto ambas extensiones activado en un buen montón de código, pero tal vez alguien con más experiencia Haskell puede pesar en cuanto a si son "mejores prácticas" o no.

Haskell 98

  1. una cabeza de ejemplo debe tener la forma C (T u1 ... uk), donde T es un constructor tipo definido por una declaración de datos o newtype (ver TypeSynonymInstances ) y la interfaz de usuario son variables de tipo diferenciado, y
  2. cada afirmación en el contexto debe tener la 'v, forma C, donde v es uno de la interfaz de usuario.

Por lo tanto, es válido utilizar instance ClassName TypeConstructor where y TypeConstructor debe ser tal que Int, Double o [a], asegúrese de que sólo puede ser un constructor de tipo involucrado !!

BTW, [] es de tipo constructor, por lo [TypeConstructor] no se puede utilizar pero se permite [NewType] y [TypeVariable].

Esta es una restricción es Haskell, y que puede evitar que al permitir FlexibleInstances .

Int y la cadena son los tipos de datos, no construtors. Cadena pasa a ser un alias para [Char], que también se puede escribir Lista Char. Un constructor de datos es algo así como Just, por lo que sólo 3 es un valor del tipo Maybe Int. Sinónimo de tipo casos se explican aquí:

http://hackage.haskell.org/trac/haskell-prime / wiki / TypeSynonymInstances

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top