extern crate alloc;
use alloc::vec::Vec;
use super::multiplicitas::Usage;
use super::qtt::Qtt;
pub trait MonasLinearis<M: Usage>: Sized {
type Elem;
type Output<B>: MonasLinearis<M, Elem = B>;
fn purus(value: Self::Elem) -> Self;
fn bind<B, F>(self, f: F) -> Self::Output<B>
where
F: FnOnce(Self::Elem) -> Self::Output<B>;
fn fmap<B, F>(self, f: F) -> Self::Output<B>
where
F: FnOnce(Self::Elem) -> B,
{
self.bind(|a| Self::Output::<B>::purus(f(a)))
}
fn then<B>(self, other: Self::Output<B>) -> Self::Output<B> {
self.bind(|_| other)
}
}
impl<A, M: Usage> MonasLinearis<M> for Qtt<A, M> {
type Elem = A;
type Output<B> = Qtt<B, M>;
#[inline]
fn purus(value: A) -> Self {
Qtt::new(value)
}
#[inline]
fn bind<B, F>(self, f: F) -> Qtt<B, M>
where
F: FnOnce(A) -> Qtt<B, M>,
{
f(self.consume())
}
}
pub struct QttMonad<A, M: Usage> {
value: Qtt<A, M>,
}
impl<A, M: Usage> QttMonad<A, M> {
#[inline]
pub fn purus(value: A) -> Self {
QttMonad {
value: Qtt::new(value),
}
}
#[inline]
pub fn from_qtt(qtt: Qtt<A, M>) -> Self {
QttMonad { value: qtt }
}
#[inline]
pub fn run(self) -> A {
self.value.consume()
}
#[inline]
pub fn into_qtt(self) -> Qtt<A, M> {
self.value
}
#[inline]
pub fn map<B, F>(self, f: F) -> QttMonad<B, M>
where
F: FnOnce(A) -> B,
{
QttMonad {
value: self.value.fmap(f),
}
}
#[inline]
pub fn flat_map<B, F>(self, f: F) -> QttMonad<B, M>
where
F: FnOnce(A) -> QttMonad<B, M>,
{
f(self.value.consume())
}
#[inline]
pub fn then<B>(self, other: QttMonad<B, M>) -> QttMonad<B, M> {
let _ = self.value.consume();
other
}
#[inline]
pub fn ap<B, F>(self, mf: QttMonad<F, M>) -> QttMonad<B, M>
where
F: FnOnce(A) -> B,
{
let f = mf.value.consume();
QttMonad {
value: Qtt::new(f(self.value.consume())),
}
}
}
impl<A: Clone, M: Usage> QttMonad<A, M>
where
Qtt<A, M>: Clone,
{
pub fn dup(&self) -> QttMonad<A, M> {
QttMonad {
value: self.value.clone(),
}
}
}
#[inline]
pub fn purus_qtt<A, M: Usage>(value: A) -> Qtt<A, M> {
Qtt::new(value)
}
#[inline]
pub fn bind_qtt<A, B, M: Usage, F>(qtt: Qtt<A, M>, f: F) -> Qtt<B, M>
where
F: FnOnce(A) -> Qtt<B, M>,
{
f(qtt.consume())
}
#[inline]
pub fn sequence_qtt<A, M: Usage>(qts: Vec<Qtt<A, M>>) -> Qtt<Vec<A>, M> {
let mut values: Vec<A> = Vec::with_capacity(qts.len());
values.extend(qts.into_iter().map(super::qtt::Qtt::consume));
Qtt::new(values)
}
#[inline]
pub fn traverse_qtt<A, B, M: Usage, F>(items: Vec<A>, f: F) -> Qtt<Vec<B>, M>
where
F: Fn(A) -> Qtt<B, M>,
{
let mut values: Vec<B> = Vec::with_capacity(items.len());
values.extend(items.into_iter().map(|a| f(a).consume()));
Qtt::new(values)
}
#[inline]
pub fn join_qtt<A, M: Usage>(nested: Qtt<Qtt<A, M>, M>) -> Qtt<A, M> {
nested.consume()
}
#[inline]
pub fn kleisli_qtt<A, B, C, M: Usage, F, G>(f: F, g: G) -> impl FnOnce(A) -> Qtt<C, M>
where
F: FnOnce(A) -> Qtt<B, M>,
G: FnOnce(B) -> Qtt<C, M>,
{
move |a| {
let b = f(a).consume();
g(b)
}
}
#[inline]
pub fn map2_qtt<A, B, C, M: Usage, F>(qa: Qtt<A, M>, qb: Qtt<B, M>, f: F) -> Qtt<C, M>
where
F: FnOnce(A, B) -> C,
{
let a = qa.consume();
let b = qb.consume();
Qtt::new(f(a, b))
}
#[inline]
pub fn map3_qtt<A, B, C, D, M: Usage, F>(
qa: Qtt<A, M>,
qb: Qtt<B, M>,
qc: Qtt<C, M>,
f: F,
) -> Qtt<D, M>
where
F: FnOnce(A, B, C) -> D,
{
let a = qa.consume();
let b = qb.consume();
let c = qc.consume();
Qtt::new(f(a, b, c))
}
#[inline]
pub fn lift2_qtt<A, B, C, M: Usage, F>(f: F) -> impl FnOnce(Qtt<A, M>, Qtt<B, M>) -> Qtt<C, M>
where
F: FnOnce(A, B) -> C,
{
move |qa, qb| map2_qtt(qa, qb, f)
}
#[cfg(test)]
mod tests {
use super::super::multiplicitas::Semel;
use super::*;
use alloc::string::ToString;
use alloc::vec;
#[test]
fn test_monas_linearis_purus() {
let q: Qtt<i32, Semel> = MonasLinearis::purus(42);
assert_eq!(q.consume(), 42);
}
#[test]
fn test_monas_linearis_bind() {
let q: Qtt<i32, Semel> = Qtt::new(5);
let result = q.bind(|x| Qtt::new(x * 2));
assert_eq!(result.consume(), 10);
}
#[test]
fn test_monas_linearis_fmap() {
let q: Qtt<i32, Semel> = Qtt::new(5);
let result = MonasLinearis::fmap(q, |x| x * 2);
assert_eq!(result.consume(), 10);
}
#[test]
fn test_monas_linearis_then() {
let q1: Qtt<i32, Semel> = Qtt::new(5);
let q2: Qtt<&str, Semel> = Qtt::new("done");
let result = q1.then(q2);
assert_eq!(result.consume(), "done");
}
#[test]
fn test_qtt_monad_purus() {
let m = QttMonad::<_, Semel>::purus(42);
assert_eq!(m.run(), 42);
}
#[test]
fn test_qtt_monad_map() {
let m = QttMonad::<_, Semel>::purus(5);
let result = m.map(|x| x * 2);
assert_eq!(result.run(), 10);
}
#[test]
fn test_qtt_monad_flat_map() {
let m = QttMonad::<_, Semel>::purus(5);
let result = m.flat_map(|x| QttMonad::purus(x + 10));
assert_eq!(result.run(), 15);
}
#[test]
fn test_qtt_monad_chaining() {
let result = QttMonad::<_, Semel>::purus(5i32)
.map(|x| x * 2)
.flat_map(|x| QttMonad::purus(x + 1))
.map(|x: i32| x.to_string())
.run();
assert_eq!(result, "11");
}
#[test]
fn test_purus_qtt() {
let q: Qtt<i32, Semel> = purus_qtt(42);
assert_eq!(q.consume(), 42);
}
#[test]
fn test_bind_qtt() {
let q: Qtt<i32, Semel> = Qtt::new(5);
let result = bind_qtt(q, |x| Qtt::new(x * 2));
assert_eq!(result.consume(), 10);
}
#[test]
fn test_sequence_qtt() {
let qs: Vec<Qtt<i32, Semel>> = vec![Qtt::new(1), Qtt::new(2), Qtt::new(3)];
let result = sequence_qtt(qs);
assert_eq!(result.consume(), vec![1, 2, 3]);
}
#[test]
fn test_traverse_qtt() {
let items = vec![1, 2, 3];
let result: Qtt<Vec<i32>, Semel> = traverse_qtt(items, |x| Qtt::new(x * 2));
assert_eq!(result.consume(), vec![2, 4, 6]);
}
#[test]
fn test_join_qtt() {
let nested: Qtt<Qtt<i32, Semel>, Semel> = Qtt::new(Qtt::new(42));
let flat = join_qtt(nested);
assert_eq!(flat.consume(), 42);
}
#[test]
fn test_kleisli_qtt() {
let f = |x: i32| Qtt::<_, Semel>::new(x + 1);
let g = |x: i32| Qtt::<_, Semel>::new(x * 2);
let composed = kleisli_qtt(f, g);
let result = composed(5);
assert_eq!(result.consume(), 12); }
#[test]
fn test_map2_qtt() {
let qa: Qtt<i32, Semel> = Qtt::new(10);
let qb: Qtt<i32, Semel> = Qtt::new(32);
let result = map2_qtt(qa, qb, |a, b| a + b);
assert_eq!(result.consume(), 42);
}
#[test]
fn test_map3_qtt() {
let qa: Qtt<i32, Semel> = Qtt::new(1);
let qb: Qtt<i32, Semel> = Qtt::new(2);
let qc: Qtt<i32, Semel> = Qtt::new(3);
let result = map3_qtt(qa, qb, qc, |a, b, c| a + b + c);
assert_eq!(result.consume(), 6);
}
#[test]
fn test_lift2_qtt() {
let add = lift2_qtt(|a: i32, b: i32| a + b);
let qa: Qtt<i32, Semel> = Qtt::new(10);
let qb: Qtt<i32, Semel> = Qtt::new(32);
let result = add(qa, qb);
assert_eq!(result.consume(), 42);
}
#[test]
fn test_left_identity() {
let a = 5;
let f = |x: i32| Qtt::<_, Semel>::new(x * 2);
let left: Qtt<i32, Semel> = MonasLinearis::purus(a);
let left_result = left.bind(f);
let right = f(a);
assert_eq!(left_result.consume(), right.consume());
}
#[test]
fn test_right_identity() {
let m: Qtt<i32, Semel> = Qtt::new(42);
let result = m.bind(Qtt::<_, Semel>::new);
assert_eq!(result.consume(), 42);
}
#[test]
fn test_associativity() {
let f = |x: i32| Qtt::<_, Semel>::new(x + 1);
let g = |x: i32| Qtt::<_, Semel>::new(x * 2);
let m1: Qtt<i32, Semel> = Qtt::new(5);
let left = m1.bind(f).bind(g);
let m2: Qtt<i32, Semel> = Qtt::new(5);
let right = m2.bind(|x| {
let fx: Qtt<i32, Semel> = Qtt::new(x + 1);
fx.bind(g)
});
assert_eq!(left.consume(), right.consume());
}
}