diff --git a/.gitignore b/.gitignore index ef05725..fcffd36 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,3 @@ book - - -# Added by cargo - -/target - - -# Added by cargo -# -# already existing elements were commented out - -#/target -/Cargo.lock +target +Cargo.lock diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 4bb75bf..d1cd34f 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -11,5 +11,7 @@ - [Chapter 2](./chapter_2.md) - [AnyStr](./exercises/anystr.md) - [Mode](./exercises/mode.md) +- [Chapter 3](./chapter_3.md) + - [Composition](./exercises/composition.md) [Topics (Spoilers)](./topics.md) diff --git a/src/chapter_3.md b/src/chapter_3.md new file mode 100644 index 0000000..9b2e616 --- /dev/null +++ b/src/chapter_3.md @@ -0,0 +1 @@ +# Chapter 3 \ No newline at end of file diff --git a/src/exercises/composition.md b/src/exercises/composition.md new file mode 100644 index 0000000..d8cf910 --- /dev/null +++ b/src/exercises/composition.md @@ -0,0 +1,115 @@ +```rust +# use std::ops::ControlFlow; + +trait Monad<'a>: 'a { + type W: 'a; + + fn map( + wa: Self::W, + f: impl FnOnce(A) -> B, + ) -> Self::W; + + fn pure( + a: A, + ) -> Self::W; + + fn collect( + wab: (Self::W, Self::W), + ) -> Self::W<(A, B)>; + + fn bind( + wa: Self::W, + f: impl FnOnce(A) -> Self::W, + ) -> Self::W; + + fn iterate( + i: impl Iteration<'a, A = A, M = Self>, + ) -> Self::W; +} + +trait Iteration<'a>: 'a + Sized { + type A: 'a; + + type M: ?Sized + Monad<'a>; + + fn next(self) -> IWrap<'a, Self>; +} + +type Wrap<'a, M, A> = >::W; + +type IOutput<'a, I> = ControlFlow<>::A, I>; + +type IWrap<'a, I> = Wrap<'a, >::M, IOutput<'a, I>>; + +struct Composition(U, V); + +impl<'a, U, V> Monad<'a> for Composition +where + U: Monad<'a>, + V: Monad<'a>, + // something missing here? +# V: Local<'a>, +{ + type W = U::W>; + + fn map( + wa: Self::W, + f: impl FnOnce(A) -> B, + ) -> Self::W { + U::map(wa, |va| V::map(va, f)) + } + + fn pure( + a: A, + ) -> Self::W { + U::pure(V::pure(a)) + } + + fn collect( + wab: (Self::W, Self::W), + ) -> Self::W<(A, B)> { + U::map(U::collect(wab), V::collect) + } + + fn bind( + wa: Self::W, + f: impl FnOnce(A) -> Self::W, + ) -> Self::W { + // impossible +# U::bind(wa, |va| U::map(V::wrap::<_, U>(V::map(va, f)), |vvb| V::bind(vvb, |vb| vb))) + } + + fn iterate( + i: impl Iteration<'a, A = A, M = Self>, + ) -> Self::W { + // impossible +# U::iterate(ComposedIteration(i)) + } +} + +# trait Local<'a>: Monad<'a> { fn wrap>(wa: Self::W>) -> M::W>; } +# struct CfInstance(ControlFlow<(), E>); +# use ControlFlow::{Continue, Break}; +# impl<'a, E: 'a> Monad<'a> for CfInstance { +# type W = ControlFlow; +# fn map(wa: Self::W, f: impl FnOnce(A) -> B) -> Self::W { +# match wa { Continue(c) => Continue(c), Break(a) => Break(f(a)) } +# } +# fn pure(a: A) -> Self::W { Break(a) } +# fn collect(wab: (Self::W, Self::W)) -> Self::W<(A, B)> { +# match wab { (Continue(e), _) => Continue(e), (_, Continue(e)) => Continue(e), (Break(a), Break(b)) => Break((a, b)) } +# } +# fn bind(wa: Self::W, f: impl FnOnce(A) -> Self::W) -> Self::W { +# match wa { Continue(e) => Continue(e), Break(a) => f(a) } +# } +# fn iterate(mut i: impl Iteration<'a, A = A, M = Self>) -> Self::W { +# loop { match i.next() { Continue(e) => break Continue(e), Break(Continue(next_i)) => i = next_i, Break(Break(a)) => break Break(a) } } +# } +# } +# struct ComposedIteration(F); +# impl<'a, U: Monad<'a>, V: Local<'a>, F: Iteration<'a, M = Composition>> Iteration<'a> for ComposedIteration { +# type A = Wrap<'a, V, F::A>; +# type M = U; +# fn next(self) -> IWrap<'a, Self> { U::map(self.0.next(), |vstate| { ControlFlow::Continue(Self(V::wrap::<_, CfInstance<_>>(vstate)?)) }) } +# } +``` diff --git a/src/topics.md b/src/topics.md index 158d159..401e95f 100644 --- a/src/topics.md +++ b/src/topics.md @@ -2,11 +2,11 @@ Rows are ordered based on estimated difficulty. -| lifetimes | `trait`s | `struct`s | +| lifetimes\[-adjacent\] | `trait`s | `struct`s | |------------------------|--------------------|-------------| | [explicit lifetimes] | [`Fn`?] | | | [extracting lifetimes] | [exclusive traits] | [`RcChars`] | -| | [`AnyStr`] | | +| [composition] | [`AnyStr`] | | | | [merging traits] | | @@ -17,3 +17,4 @@ Rows are ordered based on estimated difficulty. [exclusive traits]: ./exercises/multiple_blanket.md [merging traits]: ./exercises/modes.md [`AnyStr`]: ./exercises/anystr.md +[composition]: ./exercises/composition.md