purescript-deprecated / purescript-generics

21 stars 20 forks source link

Is there any way to get a GenericSignature from a GenericSpine? #25

Closed eskimor closed 8 years ago

eskimor commented 8 years ago

If I want to implement JSON serialization like Haskell's aeson does by default, I need to know the type signature of a type. But I only get a GenericSpine, when traversing a data structure, example:

SRecord (Array { recLabel :: String, recValue :: Unit -> GenericSpine })

From the code - I believe it is not possible, because the type information gets lost? If so, would it make sense to change GenericSpine to include the signature?

data GenericSpine = GenericSpine GenericSignature Spine

data Spine = SProd String (Array (Unit -> GenericSpine)) | SRecord (Array { recLabel :: String, recValue :: Unit -> GenericSpine }) | SNumber Number | SBoolean Boolean | SInt Int | SString String | SChar Char | SArray (Array (Unit -> GenericSpine))

To be precise: Aeson serializes constructors as simple strings, if all constructors are nullary.

Thank you!

paf31 commented 8 years ago

I don't understand the question fully, but you can get the signature now. It doesn't make sense to duplicate it in the spine in my opinion.

Also, did you see the foreign-generic library?

eskimor commented 8 years ago

Thank you for this amazingly quick answer!

I don't understand the question fully, but you can get the signature now. It doesn't make sense to duplicate it in the spine in my opinion.

I can get it when I have a value of type a. But let's say a is

data Foo = Foo Bar

with data Bar = Bar | OtherBar

now with let foo = Foo Bar I can get a spine with: toSpine foo which results in something like: SProd "Foo" [ (_ -> SProd "Bar" [])]

But for serializing: ( -> SProd "Bar" [( -> 9), (_ -> 8)]), I need to know the other constructors of Bar, in order to decide whether all constructors take zero arguments and I can thus serialize them as simple strings.

The problem arises when traversing a Spine, for any contained Prod types. I can get the signature of Foo, but not from Bar (not generically).

Is it more clear now? Am I missing something?

Also, did you see the foreign-generic library?

I did, I even started with it, but then I noticed that affjax uses Json from argonaut. Unfortunately argonaut used a different JSON encoding for Prod types than aeson.

---- Side note ---- Aeson's serialization is configurable, but I would rather adapt the client to the server, than the other way round. Also argonaut encodes the full path to the constructor like "Package.Module.Constructor", which is not desirable as the server might have a different hierarchy. In addition aeson is lacking an option for encoding a constructor that way. Meaning I have to adapt argonaut's serialization any way, I'd rather not have to adapt both server and client.

Thanks!

paf31 commented 8 years ago

My point is just that foreign-generic does something similar to what you want, I think. Perhaps the code will be useful for reference.

Normally, getting the signature is a case of passing a Proxy to getSignature, possibly using some tricks with scoped type variables to pass the right type along.

eskimor commented 8 years ago

Stupid me! Of course, I can walk the signature along with the spine. Sorry for bothering! But thanks a lot for the pointer. I will think harder next time, before opening an issue ;-)

paf31 commented 8 years ago

No problem!