-
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
How to reverse a Coproduct::subset()
after mapping both halves?
#206
Comments
This is indeed looking like it would be tough, esp the multiple applicable impls part. I wonder: would it help your usecase if (and I have yet to really think this through if it's feasible) there was a way to "dedupe" the types in a Coprod, just to get rid of the multiple impls issue (e.g. |
Hm yeah I think that would be acceptable. All that matters is that the effectful computation is able to EDIT: Although, that would throw a bit of a wrench into how I'm implementing
^ That is precisely why I have this problem in the first place (where I have two other ideas brewing:
fn reified_subset<Super, Sub, Indices, RemainderIndices>(
sup: Super
) -> (Result<Sub, Super::Remainder>, Indices, RemainderIndices)
where
Super: CoproductSubsetter<Sub, Indices>,
Super::Remainder: CoproductEmbedder<Super, RemainderIndices>,
Indices: Default,
RemainderIndices: Default,
{
(sup.subset(), Indices::default(), RemainderIndices::default())
} I think this should work because I know that the indices needed to embed the mapped subset/remainder into the final output are the same as the indices that were needed to take the subset in the first place.
|
Oh, hmmm, I thought this would work but it doesn't: use frunk::coproduct::{CoproductEmbedder, CoproductMappable, CoproductSubsetter};
use frunk::{hlist, Coprod};
pub fn challenge<
Input,
Output,
Subset,
SubsetMapper,
SubsetMapperOutput,
RemainderMapper,
RemainderMapperOutput,
Indices,
RemainderIndices,
>(
input: Input,
subset_mapper: SubsetMapper,
remainder_mapper: RemainderMapper,
) -> Output
where
Input: CoproductSubsetter<Subset, Indices>,
Input::Remainder: CoproductEmbedder<Input, RemainderIndices>, // <--------
Subset: CoproductMappable<SubsetMapper, Output = SubsetMapperOutput>,
SubsetMapperOutput: CoproductEmbedder<Output, Indices>,
Input::Remainder: CoproductMappable<RemainderMapper, Output = RemainderMapperOutput>,
RemainderMapperOutput: CoproductEmbedder<Output, RemainderIndices>, // <--------
{
match input.subset() {
Ok(subset) => {
let subset_output = subset.map(subset_mapper);
subset_output.embed()
}
Err(remainder) => {
let remainder_output = remainder.map(remainder_mapper);
remainder_output.embed()
}
}
} Usagestruct A;
struct B;
struct C;
struct D;
struct T;
struct U;
struct V;
struct W;
fn easy_mode() {
type Input = Coprod!(A, B, C, D);
type Output = Coprod!(T, U, V, W);
type Subset = Coprod!(A, B);
let subset_mapper = hlist![|A| T, |B| U];
let remainder_mapper = hlist![|C| V, |D| W];
let output: Output = challenge::<_, _, Subset, _, _, _, _, _, _>(
Input::inject(A),
subset_mapper,
remainder_mapper,
);
assert!(output.get::<T, _>().is_some());
}
fn hard_mode() {
type Input = Coprod!(A, B, C, D);
type Output = Coprod!(T, U, T, U);
type Subset = Coprod!(A, B);
let subset_mapper = hlist![|A| T, |B| U];
let remainder_mapper = hlist![|C| T, |D| U];
let output: Output = challenge::<_, _, Subset, _, _, _, _, _, _>(
Input::inject(A),
subset_mapper,
remainder_mapper,
);
assert!(output.get::<T, _>().is_some());
} Error
I assume this is because |
Oh wait! I just needed one more piece! pub fn challenge<
Input,
Output,
Subset,
SubsetMapper,
SubsetMapperOutput,
RemainderMapper,
RemainderMapperOutput,
Indices,
SubsetIndices, // <--------
RemainderIndices,
>(
input: Input,
subset_mapper: SubsetMapper,
remainder_mapper: RemainderMapper,
) -> Output
where
Input: CoproductSubsetter<Subset, Indices>,
Subset: CoproductEmbedder<Input, SubsetIndices>, // <--------
Input::Remainder: CoproductEmbedder<Input, RemainderIndices>,
Subset: CoproductMappable<SubsetMapper, Output = SubsetMapperOutput>,
SubsetMapperOutput: CoproductEmbedder<Output, SubsetIndices>, // <--------
Input::Remainder: CoproductMappable<RemainderMapper, Output = RemainderMapperOutput>,
RemainderMapperOutput: CoproductEmbedder<Output, RemainderIndices>,
{
match input.subset() {
Ok(subset) => {
let subset_output = subset.map(subset_mapper);
subset_output.embed()
}
Err(remainder) => {
let remainder_output = remainder.map(remainder_mapper);
remainder_output.embed()
}
}
} That one works! |
I have an interesting challenge:
I need to map some coproduct type
Coprod!(A, B, C, D)
toCoprod!(T, U, V, W)
. However, I have to be able to perform this mapping in two arbitrarily-partitioned steps.So I need to be able to, say, break the input into
(A, B)
and(C, D)
, then map them to(T, U)
and(V, W)
separately, then embed one of those into(T, U, V, W)
.So basically this:
Why
This is for the effect system I'm working on. When an effectful computation
a
calls another effectful computationb
, it has the option to intercept any subset of the effects thatb
raises and re-raise the rest to the caller. So in some made-up language:In Rust the effectful computations are implemented as generators where each raised effect does a
yield
of aCoprod!(<the effects>)
and awaits a message ofCoprod!(<the effect outputs>)
:This actually works for the example I gave. This compiles just fine:
The real challenge is that
T, U, V, W
are not guaranteed to be unique types. If I make the following changes:Then it fails to perform inference on the
J
andK
indices due to multiple applicable impls:So it seems I have to somehow remember the indices from the subset operation. This wouldn't be so hard if all I need to do is re-embed the
Ok()
half. I think I could make some wrapper type that remembers the indicesI
of the originalsubset()
call and uses those to embed the partial output into the final output.But the tricky bit is that I also need to be able to re-embed the remainder half into the output type.
I've been staring at the
CoproductSubsetter
code on my screen for a couple of hours now and can't figure out how one might go about doing this. Is it possible to somehow get the "inverse" of the indices inferred for thesubset()
call?The text was updated successfully, but these errors were encountered: