Hello,

On Fri, Sep 5, 2008 at 14:34, Jules Bean <jules@jellybean.co.uk> wrote:
José Pedro Magalhães wrote:
Complex has a derived instance. In Data.Complex:

   data (RealFloat a) => Complex a
     = !a :+ !a      # if __GLASGOW_HASKELL__
           deriving (Eq, Show, Read, Data)
   # else
           deriving (Eq, Show, Read)
   # endif

Was there a problem with this?


Yes, isn't it exactly the same problem as Ratio?

The derived instance 'leaks' the implementation detail of a complex number as a real and imaginary component. As part of a large structure I might want to apply some operation to all the 'Doubles' therein, but certainly not to the components of any Complex Doubles. You can imagine particular situations where I want to apply only to the real component, or something more subtle.

You can also imagine that an alternative implementation of Complexes in polar coordinates (with a suitable solution to the principle value problem) is supposed to be abstractly the same, but would gain a totally different Data instance.

I think the question here is if the datatype if abstract or not. Complex exports its (:+) constructor, so the implementation details are not hidden. Therefore it is correct to traverse its arguments. Ratio, however, does not export its (:%) constructor: Ratio is abstract, while Complex is not.

I guess then Complex should have a Data instance as it is above.

But regarding Ratio, do we want to change its gfoldl to match its current gunfoldl (as suggested before), or go the other way around, and change its gunfold, toConstr and dataTypeOf to match its gfoldl? 

If we change its gfoldl, the instance is fully defined, but does not respect the data abstraction.

If we go the other way around, the instance becomes partial (gunfold and toConstr return errors), but respects the data abstraction.

In any case, the behaviour would differ from the current. Any opinions on this?


Thanks,
Pedro