Show, Eq not necessary for Num [Was: Revamping the numeric classes]
William Lee Irwin III
wli@holomorphy.com
Sun, 11 Feb 2001 05:07:21 -0800
On 11-Feb-2001, Brian Boutel <brian@boutel.co.nz> wrote:
>> There may be some misunderstanding here. If you are talking about type
>> for which equality is always undefined, then I agree with you, but that
>> is not what I was talking about. I was thinking about types where
>> equality is defined for some pairs of argument values and undefined for
>> others - I think the original example was some kind of arbitrary
>> precision reals.
On Sun, Feb 11, 2001 at 06:24:33PM +1100, Fergus Henderson wrote:
> The original example was treating functions as a numeric type. In the
> case of functions, computing equality is almost always infeasible.
> But you can easily define addition etc. pointwise:
>
> f + g = (\ x -> f x + g x)
I have a fairly complete implementation of this with dummy instances of
Eq and Show for those who want to see the consequences of this. I found,
interestingly enough, that any type constructor f with the following
three properties could have an instance of Num defined upon f a:
(1) it has a unary constructor to lift scalars
(2) it has a Functor instance
(3) it has an analogue of zip which can be defined upon it
or, more precisely:
\begin{code}
instance (Eq (f a), Show (f a), Num a, Functor f,
Zippable f, HasUnaryCon f) => Num (f a)
where
f + g = fmap (uncurry (+)) $ fzip f g
f * g = fmap (uncurry (*)) $ fzip f g
f - g = fmap (uncurry (-)) $ fzip f g
negate = fmap negate
abs = fmap abs
signum = fmap signum
fromInteger = unaryCon . fromInteger
class Zippable f where
fzip :: f a -> f b -> f (a,b)
class HasUnaryCon f where
unaryCon :: a -> f a
instance Functor ((->) a) where
fmap = (.)
instance Zippable ((->) a) where
fzip f g = \x -> (f x, g x)
instance HasUnaryCon ((->) a) where
unaryCon = const
\end{code}
and this generalizes nicely to other data types:
\begin{code}
instance Zippable Maybe where
fzip (Just x) (Just y) = Just (x,y)
fzip _ Nothing = Nothing
fzip Nothing _ = Nothing
instance HasUnaryCon Maybe where
unaryCon = Just
instance Zippable [ ] where
fzip = zip
instance HasUnaryCon [ ] where
unaryCon = cycle . (:[])
\end{code}
On 11-Feb-2001, Brian Boutel <brian@boutel.co.nz> wrote:
>> Returning to the basic issue, I understood the desire to remove Eq as a
>> superclass of Num was so that people were not required to implement
>> equality if they did not need it, not that there were significant
>> numbers of useful numeric types for which equality was not meaningful.
On Sun, Feb 11, 2001 at 06:24:33PM +1100, Fergus Henderson wrote:
> The argument is the latter, with functions as the canonical example.
Well, usually equality as a mathematical concept is meaningful, but
either not effectively or efficiently computable. Given an enumerable
and bounded domain, equality may be defined (perhaps inefficiently)
on functions by
\begin{code}
instance (Enum a, Bounded a, Eq b) => Eq (a->b) where
f == g = all (uncurry (==))
$ zipWith (\x -> (f x, g x)) [minBound..maxBound]
\end{code}
and as I've said in another post, equality instances on data structures
expected to be infinite, very large, or where the semantics of equality
are make it difficult to compute, or perhaps even cases where it's just
not useful are also not good to be forced.
Cheers,
Bill