Derive Generic
Closed this issue ยท 17 comments
Would add a new dependency, and require a recent compiler version (>= 0.7.3).
๐
Several of the core libraries already have these constraints, so extending them to maps is fine.
๐ from me.
The issue I see here is that a Generic instance leaks the internals of the Map structure, which otherwise are not exported. I can't think of a single case where we want the sums of products representation to be available to a generic library. We want to treat it abstractly, like in aeson, where the Map constructor is matched explicitly and handled like a JSON map.
Did I miss a different use case?
What's the goal here?
My goal is to be able to easily derive Show, Eq, Ord instances. It's
already tedious as is is, compared to Haskell, having to write all these
instances manually (and also lenses). It feels like I spend half of my time
writing this boilerplate code.
On Mi., 11. Nov. 2015 at 17:48, Phil Freeman notifications@github.com
wrote:
[image: ๐] from me.
The issue I see here is that a Generic instance leaks the internals of
the Map structure, which otherwise are not exported. I can't think of a
single case where we want the sums of products representation to be
available to a generic library. We want to treat it abstractly, like in
aeson, where the Map constructor is matched explicitly and handled like a
JSON map.Did I miss a different use case?
What's the goal here?
โ
Reply to this email directly or view it on GitHub
#51 (comment)
.
Before seeing this issue I was about to write this myself. In the app I'm working on, all my models have generic instances so json based communication is super easy. I'd like to be able to do the same with Map/StrMap, so I think a generic instance would be perfect. I don't really understand how this could be a bad thing. @paf31 could you explain your remark a bit more?
Basically, a Generic instance says something is made of primitives, sums and products. Map is made of those things, but the way in which it is made up of those things is internal to the Data.Map module (the balance property of the 2-3 tree). A Generic instance for Map would necessarily expose the internals of the representation.
If we ask what a Map is, then concretely it is a balanced 2-3 tree, but abstractly it represents a partial function. The API only exposes the abstract representation.
Any Show, Eq, Ord or IsForeign instances should represent the abstract view of a Map. The ones from Generic will not do that. You'll end up showing a balanced tree, not a Map. One way to easily implement instances which represent an abstract map is to drop down to the corresponding instances for a List of Tuples.
That does make sense, thanks a lot for explaining. My current solution is
indeed to fall back to an array of tuples, but this does get more annoying
when you start nesting them, which is exactly what I love about the generic
typeclass. It's not a concern for me at the moment though, so I'm not
desperately looking for a solution โบ.
On Nov 20, 2015 9:29 PM, "Phil Freeman" notifications@github.com wrote:
Basically, a Generic instance says something is made of primitives, sums
and products. Map is made of those things, but the way in which it is
made up of those things is internal to the Data.Map module (the balance
property of the 2-3 tree). A Generic instance for Map would necessarily
expose the internals of the representation.If we ask what a Map is, then concretely it is a balanced 2-3 tree, but
abstractly it represents a partial function. The API only exposes the
abstract representation.Any Show, Eq, Ord or IsForeign instances should represent the abstract
view of a Map. The ones from Generic will not do that. You'll end up
showing a balanced tree, not a Map. One way to easily implement instances
which represent an abstract map is to drop down to the corresponding
instances for a List of Tuples.โ
Reply to this email directly or view it on GitHub
#51 (comment)
.
The nice thing about the new generics release is that we can special-case the Map type in things like foreign-generic. I've added that for Maybe already, but Map will be a bit more tricky.
What if we had a generic instance which pretended that a Map was defined like this?
data Map k v = FromArray (Array (Tuple k v))how will the fromSpine implementation for Map get a hold of the Ord k dictionary to rebuild a balanced map, unless we're assuming that the Array passed in is already, for sure, in the correct order?
Can we close this, since the goal of deriving Eq and Ord is solved now?
๐ to close. Deriving show for types that contain Maps is of course something I'd like to be able to do too, but I agree with you now, that providing a Generic Map instance is not the right way to achieve it.
How can you special-case for Maps in foreign-generic, by the way? I don't see how that would work.
You should be able to special-case by looking at the GenericSpine. However, it's missing type constructor information right now, so that needs to change. Maybe we should fix it in 0.9/1.0.0 actually. cc @garyb
I'm struggling to toJSONGeneric a StrMap (technically just ForeignโI never read from it) as part of a bigger Generic record. Is there a simple workaround?
@texastoland I have the same problem. For now I'll have to drop down to manually implementing printers/parsers.
Is there no solution for this? I also have a larger record that includes a StrMap as a field, but I can't make my record Generic if I don't have instances for all of its fields including StrMap. Going to have to look for an alternative to StrMap...
I think the solution is to use generics-rep instead. It's a better fit for cases like this.
To be clear, you still won't be able to derive Generic for Map, but you will be able to derive it for a record containing a Map as a field.