
On Thu, Jul 23, 2009 at 10:06 PM, David Menendez
On Thu, Jul 23, 2009 at 3:29 PM, Ashley Yakeley
wrote: On Thu, 2009-07-23 at 14:07 +0100, Jules Bean wrote:
Ashley Yakeley wrote:
I'm currently working on updating the Data.Fixed module in base. I am adding Typeable and Data instances (automatically derived), and several new HasResolution types (including one for 10^-2, monetary currencies being an obvious Fixed use).
Is an automatic Data instance wise?
Morally speaking does a Data.Fixed really "include" a Integer?
Compare the question: should the automatic Data instance for Complex a be used, since this exposes the fact that Complex is stored using two components in real/imaginary components?
I think that abstract types like Complex and Fixed should be treated as atoms by Data rather than being traversable, but I'm not sure.
Could you give me an example of a Data instance for either Complex or Fixed that you approve of?
Data instances unavoidably expose concrete structure. That may be the actual internal structure of the type, or it may be some constructed concrete structure, but it must be something.
For Fixed, perhaps something along the lines of the Double instance?
doubleType :: DataType doubleType = mkFloatType "Prelude.Double"
instance Data Double where toConstr = mkFloatConstr floatType -- that should probably be "doubleType" gunfold _ z c = case constrRep c of (FloatConstr x) -> z x _ -> error "gunfold" dataTypeOf _ = doubleType
You'd just need to insert some appropriate conversions between Double and Fixed.
Alternatively, you could make Fixed non-representable like Ptr,
instance Typeable a => Data (Ptr a) where toConstr _ = error "toConstr" gunfold _ _ = error "gunfold" dataTypeOf _ = mkNorepType "GHC.Ptr.Ptr"
Note that both these instances use the default definition for gfoldl, which does not attempt to descend into the structure of the data. I think this is appropriate, although whoever wrote the instance for Ratio appears to disagree with me.
I just checked the second SYB paper, http://www.cs.vu.nl/boilerplate/gmap2.pdf, and in section 5.2 it discusses primitive types. Based on that, I think StringRep is the most correct solution. Here's a quick sketch that seems to work:
import Data.Typeable import Data.Data import Data.Fixed
instance (HasResolution a) => Typeable (Fixed a) where -- omitted
fixedType :: DataType fixedType = mkStringType "Data.Fixed.Fixed"
instance (HasResolution a) => Data (Fixed a) where toConstr x = mkStringConstr fixedType (show x) dataTypeOf _ = fixedType
gunfold _ z c = case constrRep c of StringConstr s -> z (readFixed s) _ -> error "gunfold"
readFixed :: HasResolution a => String -> Fixed a readFixed s = realToFrac x where x :: Double x = read s
--
Dave Menendez