Several default implementations for instance methods

Andreas Abel abela at chalmers.se
Sat Oct 4 15:44:28 UTC 2014


Consider the following class for an overloaded pretty printer.  For
atomic data (numeric types, String etc.) one would implement
prettyShow, for complex data either pretty or prettyPrec.

 > import Text.PrettyPrint
 >
 > class Pretty a where
 >   pretty      :: a -> Doc
 >   prettyShow  :: a -> String
 >   prettyPrec  :: Int -> a -> Doc

Implementing one of these methods should be enough, giving default
implementations for the other two.

It is easy to get prettyShow and prettyPrec from pretty.

 >   prettyShow = render . pretty
 >   prettyPrec = const . pretty

However, to define pretty from one of the others, I need two default
implementations.

 >   pretty = text . prettyShow
 >   pretty = prettyPrec 0

Is there a way to get this to work?

Workarounds (not entirely satisfactory): Technically, one could define
a cycle of default implementations.  Alternative 1:

 >   pretty       = prettyPrec 0
 >   prettyShow   = render . pretty
 >   prettyPrec _ = text . prettyShow

Problem: Here, if pretty is defined,

 >   prettyPrec _ = text . render . pretty

instead of just

 >   prettyPrec _ = pretty

and (text . render) is not the identity (destroys inner document structure).

Alternative 2:

 >    pretty       = text . prettyShow
 >    prettyShow   = render . prettyPrec 0
 >    prettyPrec _ = pretty

Problem: Here, if prettyPrec is defined,

 >    pretty = text . render . prettyPrec 0

instead of just

 >    pretty = prettyPrec 0

I guess alternative 2 is worse than alternative 1, as one would
usually define prettyPrec to get pretty, and not the otherway round.
But none of these two alternatives really does the job.

-- 
Andreas Abel  <><      Du bist der geliebte Mensch.

Department of Computer Science and Engineering
Chalmers and Gothenburg University, Sweden

andreas.abel at gu.se
http://www2.tcs.ifi.lmu.de/~abel/


More information about the Haskell-prime mailing list