[Haskell-cafe] "show" for functional types
Fritz Ruehr
fruehr at willamette.edu
Mon Apr 3 06:41:37 EDT 2006
I've revised my thinking about printing (total, finite) functions: I
should have respected the notion that a printed representation can be
cut-and-pasted back in at the prompt for evaluation to something equal
to the original. I've also revised my implementation to this effect, so
that functions (over suitable classes of types) are now instances of
the classes Bounded, Enum, Eq, Ord and Show, with the desired printing,
as demonstrated by this session transcript:
> > not == not
> True
> > not == id
> False
> > id == (not . not)
> True
> > fromEnum not
> 1
> > not == toEnum 1
> True
> > not
> (\x -> case x of False -> True; True -> False)
> > not == (\x -> case x of False -> True; True -> False)
> True
> > id :: Bool -> Bool
> (\x -> case x of False -> False; True -> True)
> > const True :: Bool -> Bool
> (\x -> case x of False -> True; True -> True)
> > (&&) == (&&)
> True
> > (&&) == (||)
> False
> > fromEnum (&&)
> 8
> > (&&) == toEnum 8
> True
> > (&&)
> (\x -> case x of False -> (\x -> case x of False -> False; True ->
> False); True -> (\x -> case x of False -> False; True -> True))
The printing is a bit ugly, but it would be somewhat improved in
Haskell' if the LambdaCase suggestion is accepted (see
<http://hackage.haskell.org/trac/haskell-prime/wiki/LambdaCase>), i.e.,
without the arbitrary choice of variable, and slightly shorter
representations. Printing of properly higher-order functions doesn't
have the nice read-back property, but only because Haskell doesn't
support patterns over (suitably finite, total) functions. (One can
paste back in the printed rep. for (&&), for example, and successfully
compare it to the original, but not something of type
(Bool->Bool)->Bool.)
I can't imagine I'm the first to play around with this sort of thing,
but I wonder why instances like these ought not be included in the
Prelude. The functions are treated in a fully extensional manner, so I
think it's all quite kosher. The ideas break down for partial
functions, of course, but then so do the usual instances for enumerated
data types (we can't successfully compare True with undefined, for
example). And although the Ord and Enum instances are somewhat
arbitrary, they are coherent with each other, generated in a principled
fashion and agree with common practices (Ord and Enum for enumerated
data types are themselves somewhat arbitrary). I suppose there's an
argument from an efficiency perspective, but we don't prevent
derivation of Eq for recursive types on the grounds that someone might
compare huge trees.
Here are the instances used above (well, the headers anyway), including
products for good measure:
> instance (Enum a, Bounded a, Enum b, Bounded b) => Bounded (a->b)
> where ...
> instance (Enum a, Bounded a, Enum b, Bounded b) => Enum (a -> b) where
> ...
> instance (Enum a, Bounded a, Eq b) => Eq (a->b) where ...
> instance (Enum a, Bounded a, Enum b, Bounded b, Eq b) => Ord (a -> b)
> where ...
> instance (Enum a, Bounded a, Show a, Show b) => Show (a->b) where ...
> instance (Bounded a, Bounded b) => Bounded (a,b) where ...
> instance (Enum a, Bounded a, Enum b, Bounded b) => Enum (a,b) where ...
-- Fritz
On Apr 1, 2006, at 2:01 AM, Fritz Ruehr wrote:
> You can use type classes to implement this for *finite* functions,
> i.e., total functions over types which are Enum and Bounded (and
> Show-able), using for example a tabular format for the show:
>
> > putStr (show (uncurry (&&)))
> (False,False) False
> (False,True) False
> (True,False) False
> (True,True) True
>
> ...
More information about the Haskell-Cafe
mailing list