2015-02-23 19 views
6

Sagen Sie bitte eine Datenstruktur haben (von diesem question entlehnt):Zugriff auf die "Standard-Show" in Haskell?

data Greek = Alpha | Beta | Gamma | Delta | Eta | Number Int 

Nun kann man es eine Instanz von Show machen durch deriving Show auf diesen Befehl angehängt wird.

sagen aber wir wollen zeigen, Number Int wie:

instance Show Greek where 
    show (Number x) = show x 
    -- ... 

Das Problem ist, dass man muss alle anderen Teile der Greek Daten angeben sowie wie:

show Alpha = "Alpha" 
    show Beta = "Beta" 

Für diesen kleinen Beispiel, das ist natürlich machbar. Wenn die Anzahl der Optionen jedoch lang ist, erfordert dies viel Arbeit.

Ich frage mich, ob es möglich ist, auf die "Standard-Show" -Implementierung zuzugreifen und sie mit einem Platzhalterzeichen aufzurufen. Zum Beispiel:

instance Show Greek where 
    show (Number x) = show x 
    show x = defaultShow x 

Sie also „implementieren“ die spezifischen Muster, die aus dem Standardansatz und die verbleibenden Muster unterscheiden sich durch die „Fallback-Mechanismus“ aufgelöst.

Etwas ähnlich der Methode überschreiben mit einem Verweis auf in der objektorientierten Programmierung.

+0

Sicher, benutzen Sie einfach eine newtype Wrapper wie in der fast richtig, aber gelöscht Antwort. –

+5

Der richtige Weg, dies zu tun ist, '.. abzuleiten Show' und dann einige hübsche Druckklasse (oder nur eine Funktion), die die Daten zeigt, wie Sie möchten. Außerdem gibt es keine Methodenüberschreibung in Haskell oder "super.method", da in Haskell keine Untertypen vorhanden sind. – user2407038

+5

Die Funktion 'show' soll einen String generieren, der einen Haskell-Ausdruck enthält, der nach der Auswertung den ursprünglichen Wert zurückgibt. Wenn Sie etwas anderes benötigen, sollten Sie eine andere Funktion deklarieren (möglicherweise in einer eigenen Klasse). – chi

Antwort

7

Sie können sorta erreichen dies mit Daten und typisierbarer . Es ist natürlich ein Hack, und dieses Beispiel funktioniert nur für "aufgezählte" Typen wie in Ihrem Beispiel.

Ich bin sicher, dass wir aufwändigere bekommen konnte, wie wir dies tun, aber Ihr gegebenen Beispiel zu decken:

{-# LANGUAGE DeriveDataTypeable #-} 
import Data.Data 
import Data.Typeable 

data Greek = Alpha | Beta | Gamma | Delta | Eta | Number Int 
      deriving (Data,Typeable) 

instance Show Greek where 
    show Number n = show n 
    show x = show $ toConstr x 

Dieser Ansatz als ich realisiert habe es keine verschachtelten Datenstrukturen oder alles verarbeiten kann sonst der Ferne Lust, aber wieder, das ist ein hässlicher Hack. Wenn Sie wirklich Muss Verwendung dieser Ansatz Sie in der Data.Data Paket wühlen kann ich bin sicher, dass Sie etwas Stück zusammen könnte ...

Hier ist ein Blog-Eintrag eine kurze Einführung in die Pakete geben: http://chrisdone.com/posts/data-typeable

Der richtige Weg, um dies zu tun wäre, einen newtype Wrapper zu verwenden.Mir ist klar, dass dies nicht die bequemste Lösung ist, insbesondere bei der Verwendung von GHCi, aber es entsteht kein zusätzlicher Overhead und es ist weniger wahrscheinlich, dass es bei der Entwicklung Ihres Programms unerwartete Wege einschlägt.

data Greek = Alpha | Beta | Gamma | Delta | Eta | Number Int 
     deriving (Show) 

newtype SpecialPrint = SpecialPrint Greek 

instance Show SpecialPrint where 
    show (SpecialPrint (Number x)) = "Number: " ++ show x 
    show (SpecialPrint x) = show x 

main = do 
    print (SpecialPrint Alpha) 
    print (SpecialPrint $ Number 1) 
+3

Ich denke, Sie könnten eine ähnliche Sache wie die erste Variante mit [Generic-Deriving] erreichen (http://hackage.haskell.org/package/generic-deriving-1.7.0/docs/Generics-Deriving-Show.html) , die wahrscheinlich auch verschachtelte Dinge behandeln würde (solange alles "Generic" ist). – phg

7

Nein, das ist nicht möglich AFAIK.

Weitere, benutzerdefinierte Instanzen von Show verdienen einen zweiten Gedanken, denn Show und Read Instanzen sollten miteinander kompatibel sein.

Verwenden Sie für die einfache Umwandlung in menschliche (oder wer auch immer) lesbare Strings Ihre eigene Funktion oder eigene Typklasse. Dies wird auch erreichen, was Sie wollen:

Angenommen, Sie haben einen Presentable typeclass mit einem Verfahren present, und auch das Standard-Show Beispiel können Sie schreiben:

instance Presentable Greek where 
    present (Number x) = show x 
    present x = show x 
6

Wie @phg oben in Kommentar wies dies kann auch mit Hilfe von generic-deriving erfolgen:

{-# LANGUAGE DeriveGeneriC#-} 
module Main where 

import   Generics.Deriving.Base (Generic) 
import   Generics.Deriving.Show (GShow, gshow) 

data Greek = Alpha | Beta | Gamma | Delta | Eta | Number Int 
    deriving (Generic) 

instance GShow Greek 
instance Show Greek where 
    show (Number n) = "n:" ++ show n 
    show l = gshow l 

main :: IO() 
main = do 
    print (Number 8) 
    print Alpha 
Verwandte Themen