diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7585238 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +book diff --git a/book.toml b/book.toml new file mode 100644 index 0000000..caea406 --- /dev/null +++ b/book.toml @@ -0,0 +1,16 @@ +[book] +authors = ["Alisa Feistel"] +language = "en" +multilingual = false +src = "src" +title = "Monads in Rust" + +[build] +build-dir = "book" +create-missing = false + +[output.html] +default-theme = "navy" +mathjax-support = true +git-repository-url = "https://gitea.parrrate.ru/PTV/radn-rs" +edit-url-template = "https://gitea.parrrate.ru/PTV/radn-rs/_edit/main/book/{path}" diff --git a/src/SUMMARY.md b/src/SUMMARY.md new file mode 100644 index 0000000..0f6afcf --- /dev/null +++ b/src/SUMMARY.md @@ -0,0 +1,12 @@ +# Summary + +[Introduction](./ch00/s00-introduction.md) + +- [Background](./ch01/s00-background.md) +- [Implementation](./ch02/s00-implementation.md) +- [Usage]() +- [Current Implementation Concerns](./ch04/s00-concerns.md) + - [Alternative Monad Traits](./ch04/s01-alternatives.md) + - [Lifetimes](./ch04/s02-lifetimes.md) + - [Stackless](./ch04/s03-stackless.md) + - [Covariance](./ch04/s04-covariance.md) diff --git a/src/ch00/s00-introduction.md b/src/ch00/s00-introduction.md new file mode 100644 index 0000000..e10b99d --- /dev/null +++ b/src/ch00/s00-introduction.md @@ -0,0 +1 @@ +# Introduction diff --git a/src/ch01/s00-background.md b/src/ch01/s00-background.md new file mode 100644 index 0000000..5767328 --- /dev/null +++ b/src/ch01/s00-background.md @@ -0,0 +1 @@ +# Background diff --git a/src/ch02/s00-implementation.md b/src/ch02/s00-implementation.md new file mode 100644 index 0000000..d2557ff --- /dev/null +++ b/src/ch02/s00-implementation.md @@ -0,0 +1 @@ +# Implementation diff --git a/src/ch04/s00-concerns.md b/src/ch04/s00-concerns.md new file mode 100644 index 0000000..146cac8 --- /dev/null +++ b/src/ch04/s00-concerns.md @@ -0,0 +1,19 @@ +# Concerns (questions) with the current implementaion + +## There exist alternative `Functor` implementations + +See the [relevant subchapter](s01-alternatives.md) + +## It might be better to have a per-lifetime trait for `Functor`s + +See the [relevant subchapter](s02-lifetimes.md) + +## `Stackless` is kind of bad + +See the [relevant subchapter](s03-stackless.md) + +## `WeakFunctor::F<'a, A>` is not (yet) covariant over the lifetime `'a` + +See the [relevant subchapter](s04-covariance.md) + +## Can `WeakFunctor` be an associated type of a `Functor` instead of its supertype? diff --git a/src/ch04/s01-alternatives.md b/src/ch04/s01-alternatives.md new file mode 100644 index 0000000..735e65b --- /dev/null +++ b/src/ch04/s01-alternatives.md @@ -0,0 +1,97 @@ +# Atlernatives to `Functor` trait + +## `_`-`FnOnce` category functors (current) + +Copied for reference. All following examples are in the same `Functor`-`Applicative`-`Monad` format +without extra (sub)traits like `WeakFunctor`, `Pure`, `ApplicativeLA2`, etc. . + +```rust +trait Functor { + type F<'a, A: 'a>: 'a + where + Self: 'a; + + fn fmap<'a, A: 'a, B: 'a>( + f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>, + ) -> Self::F<'a, B> + where + Self: 'a; +} + +fn fmap<'a, T: 'a + Functor, A: 'a, B: 'a>( + f: impl 'a + FnOnce(A) -> B, +) -> impl FnOnce(T::F<'a, A>) -> T::F<'a, B> { + |fa| T::fmap(f, fa) +} +``` + +## `Clone`-`Fn` category functors + +This is probably the closest representation to what Haskell views as a category of its types. + +```rust +trait Functor: Clone { + type F<'a, A: 'a + Clone>: 'a + Clone + where + Self: 'a; + + fn fmap<'a, A: 'a + Clone, B: 'a + Clone>( + f: impl 'a + Clone + Fn(A) -> B, fa: Self::F<'a, A>, + ) -> Self::F<'a, B> + where + Self: 'a; +} + +fn fmap<'a, T: 'a + Functor, A: 'a + Clone, B: 'a + Clone>( + f: impl 'a + Clone + Fn(A) -> B, +) -> impl 'a + Clone + Fn(T::F<'a, A>) -> T::F<'a, B> { + move |fa| T::fmap(f.clone(), fa) +} +``` + +## `Clone`-`FnMut` category functors + +We view use of `FnMut` for category's morphisms as somewhat controversial[^e]. +* Use of direct/indirect mutable references is, arguably, counter-functional[^e]. +* `Clone+FnMut` is, generally, nonsensical[^e]. +* Due to that, morphisms category isn't a subcategory, so can't be wrapped. +* Not being to wrap morphisms makes implementation of one specific `Applicative` method, +sequential application (`<*>` in Haskell, `seq` in RADN) *difficult*. + +```rust +trait Functor: Clone { + type F<'a, A: 'a + Clone>: 'a + Clone + where + Self: 'a; + + fn fmap<'a, A: 'a + Clone, B: 'a + Clone>( + f: impl 'a + FnMut(A) -> B, fa: Self::F<'a, A>, + ) -> Self::F<'a, B> + where + Self: 'a; +} +``` + +[^e]: elaborate? + +## `Copy`-`Fn` category functors + +```rust +trait Functor: Copy { + type F<'a, A: 'a + Copy>: 'a + Copy + where + Self: 'a; + + fn fmap<'a, A: 'a + Copy, B: 'a + Copy>( + f: impl 'a + Copy + Fn(A) -> B, fa: Self::F<'a, A>, + ) -> Self::F<'a, B> + where + Self: 'a; +} + +fn fmap<'a, T: 'a + Functor, A: 'a + Copy, B: 'a + Copy>( + f: impl 'a + Copy + Fn(A) -> B, +) -> impl 'a + Copy + Fn(T::F<'a, A>) -> T::F<'a, B> { + move |fa| T::fmap(f, fa) +} +``` diff --git a/src/ch04/s02-lifetimes.md b/src/ch04/s02-lifetimes.md new file mode 100644 index 0000000..0ff255b --- /dev/null +++ b/src/ch04/s02-lifetimes.md @@ -0,0 +1,18 @@ +# Making lifetimes a parameter of a trait instead of that of the GAT + +Current: +```rust +pub trait WeakFunctor { + type F<'a, A: 'a>: 'a + where + Self: 'a; +} +``` + +Proposed: +```rust +pub trait WeakFunctor<'a>: 'a { + type F: 'a; +} +``` + diff --git a/src/ch04/s03-stackless.md b/src/ch04/s03-stackless.md new file mode 100644 index 0000000..ee7c427 --- /dev/null +++ b/src/ch04/s03-stackless.md @@ -0,0 +1,5 @@ +# `Stackless<'a>` isn't covariant + +Current hypothesis is that this comes from `EvalTree<'a>` being invariant over `'a` +due to `FnOnce` being invariant over its output, +which in turn comes from present typesysten limitations. diff --git a/src/ch04/s04-covariance.md b/src/ch04/s04-covariance.md new file mode 100644 index 0000000..0cb0c7a --- /dev/null +++ b/src/ch04/s04-covariance.md @@ -0,0 +1,5 @@ +## `CovariantFunctor` not (yet) included in `Monad` + +## Specific case: `Stackless<'a>` isn't covariant + +See the [relevant subchapter](s03-stackless.md)