2012-09-11 3 views
1

Je veux une place représentation séparée de saut de ligne de la virgule habituelle séparés l'un, pour tyepe nouvelle de données peut:surcharge spectacle pour la liste

newtype SimpleRecord = SimpleRecord ([Char], [Char], Integer) 
    deriving (Show) 

J'ai essayé d'écrire cette istance de Show class:

instance Show [SimpleRecord] where 
     show [(SimpleRecord (n, i, c))] = show (SimpleRecord (n, i, c))++['\n'] 
     show (l:ls) = (show l)++['\n']++(show ls) 

GHC m'insulte fortement. Est-ce que quelqu'un peut essayer de m'expliquer ce que je peux faire?

+3

La classe 'show' a une méthode' showList' de sorte que vous pouvez les personnaliser. C'est ainsi que les chaînes alias '[Char]' sont affichées différemment. Remarque - vous ne pouvez pas dériver 'Show' pour SimpleRecord, vous devez le faire vous-même et définir' showList' en même temps. –

+1

Vous pouvez écrire une fonction qui n'est pas appelée 'show' et l'utiliser. – AndrewC

Répondre

2

D'abord, la classe Show est supposée être pour produire le code source Haskell, qu'il ne devait pas la classe Read peut alors lire avant. être pour produire une sortie "jolie" lisible par l'homme. Après avoir dit cela, presque tout le monde l'utilise à mauvais escient pour ce dernier, et cela peut être utile à des fins de débogage.

Ainsi, vos options sont:

  1. Ecrire une fonction pas appelé show qui fait ce que vous voulez. (Comme commentaire de AndrewC.)

  2. Utilisez la méthode showList.

Si vous écrivez deriving Show, cela indique au compilateur d'écrire toutes les méthodes Show pour vous. Si vous voulez les écrire vous-même, vous devez d'abord supprimer le bit deriving. Ensuite, vous pouvez écrire votre exemple, qui va ressembler à quelque chose comme

instance Show SimpleRecord where 
    show (SimpleRecord (x, y, z)) = ... 

    showList rs = unlines (map show rs) 

En aparté, si vous ne saviez pas déjà, vous pouvez écrire

mapM_ print records 

au GHCi invite à imprimer liste de choses imprimables avec un élément par ligne.


En asside finale, pourquoi

newtype SimpleRecord = SimpleRecord ([Char], [Char], Integer) 

plutôt que

data SimpleRecord = SimpleRecord [Char] [Char] Integer 
+0

Non (à nouveau) - 'Show' n'est pas censé être pour _producing Haskell output_. Il sert à convertir les valeurs Haskell en chaînes. Veuillez lire le chapitre pertinent dans le rapport Haskell. Bien sûr, il existe des avantages si vous avez une correspondance entre les instances de lecture et de lecture, mais il n'y a aucune obligation pour cela. –

+0

@stephentetley de la section sur les instances 'Show' dérivées:" Le résultat de show est une expression Haskell syntaxiquement correcte ... ". Bien qu'il n'y ait aucune obligation que les instances 'Show' personnalisées se comportent de cette façon, il est * intentionnellement la valeur par défaut. http://www.haskell.org/onlinereport/haskell2010/haskellch11.html#x18-18600011.4 –

1

Votre question est assez ambiguës. Si j'interprète correctement, vous essayez de changer l'instance Show par défaut pour [SimpleRecord].

Comme GHC a déjà défini l'instance Show [a] lorsque Show a est défini. Vous obtenez l'erreur suivante (après avoir inclus l'extension FlexibleInstances) lorsque vous essayez de définir à nouveau l'instance pour Show [SimpleRecord].

Matching instances: 
     instance Show a => Show [a] -- Defined in `GHC.Show' 
     instance Show [SimpleRecord] -- Defined at show.hs:5:11 

Vous devez utiliser OverlappingInstances extension de la langue pour permettre le surcharger. Il indique que GHC doit correspondre à l'instance la plus spécifique.

Vous pouvez également inclure FlexibleInstances extension, ce qui permet de parler de types imbriqués arbitraires déclaration d'instance ..

{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE OverlappingInstances #-} 
newtype SimpleRecord = SimpleRecord ([Char], [Char], Integer) 
    deriving (Show) 

instance Show [SimpleRecord] where 
    show [SimpleRecord (n, i, c)] = show (SimpleRecord (n, i, c))++"\n" 
    show (l:ls) = show l ++ "\n" ++ show ls 

Vous obtenez plus d'informations sur ces extensions de langue à GHC Docs

Juste un commentaire sur la conception de votre type, il est préférable de définir votre type comme

data SimpleRecord = SimpleRecord String String Integer 

Vous obtenez mo re flexibilité ici en termes d'application constructeur partiel etc.

+2

Ce serait le cas pour la plupart des classes. Mais 'Show' contient un hack horrible pour exactement cette situation. Vous pouvez fournir une implémentation différente de 'showList' pour votre type afin de personnaliser la gestion des listes de votre type. – Carl

+0

Cela vaut-il également la peine de souligner que cette occurrence d'occurrence a une correspondance de motif non-exaustive? – Phyx

1

Je pourrais avoir manqué quelque chose, mais il n'était pas clair pourquoi vous étiez newtyping (String, String, Integer) plutôt que ce que vous étiez concerné pour montrer gentiment, à savoir listes d'entre eux. Ensuite, vous échapper à l'instance universelle Afficher pour les listes:

newtype SimpleRecords = SimpleRecords [(String, String, Integer)] 

instance Show SimpleRecords where 
    show (SimpleRecords []) = "" 
    show (SimpleRecords ((n, i, c): xs)) = 
     show (n, i, c) ++ "\n" ++ show (SimpleRecords xs) 

-- Prelude Main> let a = words "We hold these truths to be self-evident" 
-- Prelude Main> let b = words "All the best people are using Clorox" 
-- Prelude Main> let c = zip3 a b [1::Integer ..] 
-- Prelude Main> SimpleRecords c 
-- ("We","All",1) 
-- ("hold","the",2) 
-- ("these","best",3) 
-- ("truths","people",4) 
-- ("to","are",5) 
-- ("be","using",6) 
-- ("self-evident","Clorox",7) 
Questions connexes