Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    daboross
    @daboross

    Hi!

    I was wondering if this is a problem that could be solved by frunk - I have many persistent structs which will be receiving "updates" periodically, and I'd like to avoid writing boilerplate for setting each individual field of each struct.

    Update transaction would be something like this:

    let init = hlist![1, 2, 3];
    let update = hlist![None, Option(5), None];
    
    let result; // = ?;
    assert_eq!(result, hlist![1, 5, 3]);
    even better if this could be done directly "to" a #[derive(Generic)] struct, but that wouldn't be needed and performance isn't key here
    daboross
    @daboross
    hmm, I thought I could do something with Semigroup, but it doesn't seem so
    daboross
    @daboross
    I guess I'll just be doing updates by hand for now
    Lloyd
    @lloydmeta
    @daboross there's a semigroup for Option inside HList that could work here
    Sorry for the late reply, I thought I was getting all email notifications for Gitter; turns out it sends them out selectively at random..
    Lloyd
    @lloydmeta

    Actually looking at this again, I don't think the Semigroup for Option would work here. Maybe you need to define your own newtype with its own Semigroup instance

    Maybe something like (not tested..may not compile)

    enum Updateable<A> {
      NoUpdate,
      UpdateWith(A)
    }
    
    impl <A> Semigroup for Updateable<A> {
        fn combine(&self, other: &Self) -> Self {
           // some your update logic here based on type of self and other
        }
    }

    That said, it looks kind of dubious in that it might not follow Semigroup laws, so tread carefully.

    daboross
    @daboross

    thank you for the reply! I think this is similar to what I want, but probably not exactly. Right now I ended up just using a macro surrounding each struct which defines an update method, it works fairly well.

    Main reason I don't think Semigroup would work is the requirement that the update and the updateable have to be the same type - the actual data I'm storing doesn't have a valid None state - but the updates do.

    For instance, a data/update pair might be:

    struct Road {
        x: i16,
        y: i16,
        room: RoomName,
        next_decay: Option<u64>,
    }
    struct RoadUpdate {
        x: Option<i16>,
        y: Option<i16>,
        room: Option<RoomName>,
        next_decay: Option<Option<u64>>,
    }
    I do have a working solution with a macro right now, that's working alright - it would be interesting to see if frunk can deal with this but I can imagine if it can't that's reasonable
    Lloyd
    @lloydmeta

    Main reason I don't think Semigroup would work is the requirement that the update and the updateable have to be the same type

    Yeah, I think as a result Semigroup isn't a good fit here. Maybe your macro solution is the simplest and sanest way :)

    Klas Segeljakt
    @segeljakt
    Hello
    Diggory Blake
    @Diggsey
    hi
    Jack Wrenn
    @jswrenn

    @lloydmeta (or anyone else), I'm doing some type-level programming and I've encountered a pattern that consistently trips up the compiler, and I'm not sure why. I'm wondering if you might have any insight.

    Let's say we define a type-level, non-empty list:

    struct COne<H>(PhantomData<H>);
    struct CCons<H, T>(PhantomData<(H,T)>);

    ...and a Contains<E> trait that's satisfied for that list if E is in it:

    #[marker]
    trait Contains<E> {}
    
    /// The needle is the only element of the list.
    impl<H> Contains<H> for COne<H> {}
    
    /// The needle is the first element of the list.
    impl<H, T> Contains<H> for CCons<H, T> {}
    
    /// The needle is in the tail of the list.
    impl<E, H, T> Contains<E> for CCons<H, T>
    where T: Contains<E>
    {}

    This works completely fine. However, if we wrap each of those types in another type:

    struct Wrap<T>(T);
    
    /// The needle is the only element of the list.
    impl<H> Contains<Wrap<H>> for Wrap< COne<H> > {}
    
    /// The needle is the first element of the list.
    impl<H, T> Contains<Wrap<H>> for Wrap< CCons<H, T> > {}
    
    /// The needle is in the tail of the list.
    impl<E, H, T> Contains<Wrap<E>> for Wrap< CCons<H, T> >
    where Wrap<T>: Contains<Wrap<E>>
    {}

    ...then the compiler fails, overflowing evaluating the requirement Wrap<COne<_>>: Contains<Wrap<_>>.

    Playground link here: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=a6699469d9ef51a0cad5d6f120e35eb5

    setzer22
    @setzer22
    Hi! :smile: I came across frunk and I must say it looks pretty awesome! After reading about LabelledGeneric, I was wondering: Is there a way I can use it to iterate over the fields of a struct? Sorta like reflection in other languages
    Lloyd
    @lloydmeta
    :wave: yeah something like reflection (but not exactly.... all type info at compile-time only..):
    // mapping over generic representation
    let peep = Person {
        first_name: "bo",
        last_name: "peep",
        age: 30,
    };
    let generic = frunk::into_generic(peep);
    // mapping each one
    let _ = generic.map(hlist![
        |first_name| println!("First name: {}", first_name),
        |last_name| println!("Last name: {}", last_name),
        |age| println!("age: {}", age),
    ]);