2012-10-10 28 views
5

Supongamos que quisiera crear un nuevo tipo de datos y mostrar los constructores, solo en minúsculas en lugar de su definición en mayúscula. Por ejemplo:Cómo mostrar un constructor en minúsculas

data Day = Monday | Tuesday | Wednesday| Thursday | Friday | Saturday | Sunday 

Mediante la adición de derivar Mostrar, ghci imprimiría ellos como "los lunes, martes, etc .." Para conseguirlo para mostrar "lunes, martes, etc .." He tratado de hacer un caso especial de espectáculo:

import Data.Char 

strToLower :: [Char] -> [Char] 
strToLower (x:xs) = toLower x : strToLower xs 
strToLower [] = [] 

instance Show Day where 
    show d = strToLower (show d) 

donde la primera aparición del espectáculo debe designar a mi nueva función de presentación de enmiendas (que se denominará cada vez que imprimo), mientras que para el segundo intento utilizar la versión de show normalmente derivada, para pasar del nombre del constructor a una Cadena.

Por supuesto, esto no funciona (definición circular) ya que el ghci no tiene ni idea de mis significados por separado de la palabra "mostrar", pero no entiendo cómo hacerle saber la distinción, ya que ambas versiones necesitan ser nombrado show, el primero porque a eso es a lo que llama la impresión y el segundo porque es una función haskell predefinida que puede darme una cadena de un nombre de constructor. He intentado

show d = strToLower ((showsPrec 0 d) "") 

pero esto se reduce a la misma definición circular, al menos eso es lo que supongo que desde el ghci quedar atrapado en un bucle.

Entiendo por qué los nombres de los constructores deben comenzar con una letra mayúscula, pero mostrarlos en minúscula no debería ser un problema, ¿o sí? Sé que podría definir mi función de presentación para cada caso por separado, p. Ej. show Monday = "monday"show Tuesday = "tuesday" etc., pero solo estoy usando los días de la semana como ejemplo y mi tipo de datos real consta de 64 constructores, por lo que creo que sería más elegante resolverlo de manera diferente de alguna manera.

¿Es posible profundizar en la definición de haskell de mostrar y modificar una copia de ese código? Esta es la única solución posible que se me ocurre, pero no sé cómo hacerlo, si es posible. Probablemente no. ¡Entonces otras soluciones también son bienvenidas!

Gracias por tomar su tiempo,

Jelle (principiante Haskell)

+4

¿Por qué no puedes escribir 'showDay day = map to Low. show' y use 'showDay' en lugar de' show'? – dave4420

+0

Además de las otras respuestas, podría valer la pena responder a su pregunta directa (¿cómo puedo usar el 'show' derivado para implementar mi propio' show'?), Para lo cual la respuesta es "no se puede". Es una regla fundamental de Haskell que cada clase pueda tener en la mayoría de una instancia para un tipo dado. –

Respuesta

9

En realidad se puede hacer esto utilizando las Typeable y Data clases.

Para ello es necesario la extensión DeriveDataTypeable, encenderlo con -XDeriveDataTypeable o poniendo la siguiente línea al inicio del archivo que define su tipo:

{-# LANGUAGE DeriveDataTypeable #-} 

Ahora puede importar los módulos necesarios:

import Data.Data 
import Data.Typeable 

y derivar Typeable y Data:

data Day = Monday | Tuesday | Wednesday| Thursday | Friday | Saturday | Sunday 
    deriving (Typeable, Data) 

Ahora puede utilizar toConstr para obtener una representación constructor:

instance Show Day where 
    show = strToLower . showConstr . toConstr 

Pero ver las otras respuestas acerca de si usted realmente desea, en lugar de simplemente utilizar una función showDay o en su propio tipo de clase en su lugar.

+0

+1 Gracias ... No esperaba que esto se pudiera hacer ... – Satvik

+0

¡Muchas gracias! Prefiero esta solución porque es fácil y conserva la noción pura de "demostrable" en lugar de tener que recurrir a una función de espectáculo "falsa" (mi). ¡Gracias de nuevo! – user1734761

+0

Aún así, no construiría una instancia 'Show' porque su resultado no es el código Haskell válido. Pero esta es una manera realmente agradable de definir una función de demostración 'showDay' o class-type personalizada, +1. - En una nota no relacionada, escribir expresiones de la forma 'f $ g $ x' es [tipo de obsoleto] (http://stackoverflow.com/a/8618901/745903), use el equivalente' f. g $ x' en su lugar (por lo que en este caso 'show d = strToLower. showConstr $ toConstr d'). – leftaroundabout

3

Bueno no sé si se puede hacer que para un mismo tipo de datos, pero una solución que puedo ver es envolver en un newtype como

newtype D = D Day 
instance Show D where 
    show (D d) = strToLower $ show d 

ya se puede utilizar en lugar de tipo DDay.

+0

... a costa de tener que escribir '(D lunes)' en lugar de 'lunes'. (No diciendo que esto es una mala idea, necesariamente, solo que tiene sus desventajas). – dave4420

+0

@ dave4420 Bueno, él puede por supuesto definir alguna otra función en lugar de 'show', pero la función' show' podría ser utilizada por otras funciones de la biblioteca, por lo que no puedo simplemente modificar eso. Es la compensación de la que estoy hablando, por eso dije que es una solución alternativa, con algún costo que pagar por escribir esos constructores adicionales. – Satvik

6

Se supone que las instancias de la clase Show funcionan de tal manera que puede copiar y pegar su salida y usarla como código Haskell. Si ahora tiene constructores en minúscula, estos no funcionarán como tales. Que trabajarían con el enfoque newtype,

data DayInternal = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday 

newtype Day = Day DayInternal 
monday = Day Monday 
tuesday = Day Tuesday 
wednesday = Day Wednesday 
thursday = Day Thursday 
friday = Day Friday 
saturday = Day Saturday 
sunday = Day Sunday 

instance Show Day where 
    show (Day d) = strToLower $ show d 

Por supuesto, que te deja con la redundancia es probable que no le gusta. Puedes construir esto automáticamente con Template Haskell, pero dudo que valga la pena.

Lo que realmente creo es que no es una instancia de Show, sino más bien una especie de impresión bonita.Se podría rodar su propia

class MyNiceShow s where 
    myNiceShow :: s -> String 

data Day = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday 
     deriving (Show) 

instance MyNiceShow Day where 
    myNiceShow d = strToLower $ show d 
+0

No creo que escribir todas esas funciones (incluso por TH) sea de alguna utilidad porque no puede coincidir con el patrón en ellas y creo que la mayor parte de la escritura de esos constructores se usará en la coincidencia de patrones. – Satvik

+0

También es muy inútil agregar una nueva clase de letra para simplemente escribir show, ya que tendrá que definir instancias para otras clases o usar directamente la función que simplemente se reduce a lo que Dave sugirió (escriba una función de myshow). – Satvik

+1

No, puede definir 'MyNiceShow' de una manera para usar' Show' para todos los demás tipos (usando #OverlappinInstances, pero bueno ...). – Landei

Cuestiones relacionadas