-
Notifications
You must be signed in to change notification settings - Fork 58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generic for enums <-> Coproducts #114
Comments
Multi field variants
I don't think this needs to be a problem, we could convert the following enum Foo {
Var1(A, B, C),
Var2(D, E),
Var2 {
field: F,
},
Nil,
Red
} to: impl Generic... {
type Repr = Coprod!(
Hlist![A, B, C],
Hlist![D, E],
Hlist[F],
(),
(),
);
} Recursive typesWhat worries me more are recursive types, c.f: enum List<T> {
Nil,
Cons(Box<List<T>>),
} We can translate this to: |
Something does feel off to me about the asymmetry between I don't see any issue with the fact that |
Ahh, just one thing: If the user wants to query what variant of the enum their Coproduct is, this will be difficult to do since the types of the variants cannot be easily written and may collide with each other (e.g. for unit variants). (note: I do admit that the use cases for querying the variant of Generic output are limited, since it's really supposed to be for SYB purposes) Reified indices could help here (which again is something I want to consider post-0.2.0) |
I guess
Do you remember how Haskell does this (https://hackage.haskell.org/package/base-4.11.0.0/docs/GHC-Generics.html) ?
I think this is somewhat what GHC does? |
Oh, I think I see the issue now. For some SYB trait implementations, |
(There's also blog post: http://fitzgeraldnick.com/2017/08/03/scrapmetal.html |
It would definitely be nice to figure out a nice way to get enums working with I think I attempted to do this before, but ran into snags that you have already mentioned; e.g. enum-variants aren't types. The other part of this is, I couldn't really come up with a good use-case for it myself. E.g. if one has an For instance, if we just take the types of each enum member as enum Pets {
Dog,
Horse,
Cat(i32),
Snake(i32),
}
enum Colours {
Red,
Yellow,
Blue(i32),
Green(i32),
} In addition; with a If I'm not taking crazy pills, and these are indeed valid concerns, would it be OK to fail derivation when we resolve the same types for more than 1 enum member ? |
RE: Variants with matching types: It may be difficult to work with the encoded form directly, but I believe there are still use cases for writing generic abstractions (SYB style). I feel // horribly made-up example
pub enum Counts {
None,
Red(i32),
Blue(i32),
Both { red: i32, blue: i32 },
} I can picture getting a total count out of the above with a Poly func that is implemented on Moreover, a common pattern in my own code is stuff like the following: pub enum CoordsKind<V> {
Cart(V),
Frac(V),
} And I frequently have helper functions like the following, to help with the implementation of other things: // once I have these three things, I seldom ever need to write a `match` expression again,
// except in cases where the behavior of Frac/Cart are legitimately different
impl<V> CoordsKind<V> {
fn as_refs(&self) -> CoordsKind<&V> { ... }
fn as_muts(&mut self) -> CoordsKind<&mut V> { ... }
fn map<U, F>(self, f: F) -> CoordsKind<U>
where F: FnOnce(V) -> U,
{ ... }
fn fold<U, F>(self, f: F) -> U
where F: FnOnce(V) -> U,
{ ... }
} It often feels to me like there ought to be some way I could use Generic to accomplish some of this stuff. But I haven't really thought too hard about it yet to know how well it works out.
They could; Mind; for the most part, reified indices doesn't add very many new capabilities, at least not strictly speaking. For the most part, they are simply a far-more-ergonomic alternative to manually specifying the Index param through UFCS. However, thanks to that, they make it reasonable to have public APIs where the user specifies the index, which in turn allows us to reasonably add methods to the API where the type of the element at a given index is given by an associated type rather than a type parameter. (and that could be considered to be the foundation for the new capabilities it adds) |
Ah interesting; I hadn't thought of that. Interesting food for thought :) Thanks. |
Also, I wonder if it would be worthwhile to add something like the following to fn repr_map<Repr, Mapper>(self, mapper: Mapper) -> Self // Bikeshed on name
where
Self: Generic<Repr = Repr> + Sized,
Mapper: FnOnce(Repr) -> Repr
{
Self::from(mapper(self.into()))
} This lets you apply a function to the |
Oh interesting indeed; that would make it easy to apply the same |
Just wanted to put this here. There is now an RFC for making enum variants actual types: rust-lang/rfcs#2593 |
What about deriving |
Probably, yes. There is a bit of ambiguity though: Enum variants have fields themselves, so
(of course, we can still also have Doubling down doesn't sound like too bad of an idea, though it may annoy some users who get more than they bargained for. Eh. I've been mostly fine without the feature, so I haven't put that much energy into thinking about it since making the issue. If anybody can get it to work, PRs are welcome! |
So, obviously,
struct
s are toHList
s asenum
s are toCoproduct
s. Frunk has both of these data types, so why doesn't it implementGeneric
for enums yet?After thinking about this a bit, it occurred to me that there's a nontrivial technical challenge here, due to the fact that rust doesn't consider enum variants to be types. Basically, we'd have to do something like one of the following:
Option<T>
. Should the None type have type parameters? If so, does the user need to add phantom fields?)The text was updated successfully, but these errors were encountered: