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.a...@gu.se
http://www2.tcs.ifi.lmu.de/~abel/
_______________________________________________
Haskell-prime mailing list
Haskell-prime@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-prime

Reply via email to