use batch_impl::batch_trait;
use crate::op::{Additive, Multiplicative};
use crate::tower::{Magma, Monoid, Semigroup};
batch_trait! {
Magma: <T: @trait<>> @trait[<Additive>,<Multiplicative>] Option<T>{
fn combine(&self, rhs: &Self) -> Self {
match (self, rhs) { (Some(a), Some(b)) => Some(a.combine(b)), _ => None }
}
};
Semigroup: <T: @trait<>> @trait[<Additive>,<Multiplicative>] Option<T>;
Monoid: <T: @trait<>>[{
fn identity() -> Self { None }
}, @trait<Multiplicative>{
fn identity() -> Self { Some(T::identity()) }
}] Option<T>;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tower::Magma;
fn add<T: Magma<Additive>>(a: T, b: T) -> T {
<T as Magma<Additive>>::combine(&a, &b)
}
fn mul<T: Magma<Multiplicative>>(a: T, b: T) -> T {
<T as Magma<Multiplicative>>::combine(&a, &b)
}
#[test]
fn option_additive_monoid() {
let id = <Option<u8> as Monoid<Additive>>::identity();
assert_eq!(id, None);
assert_eq!(add(Some(3u8), Some(4)), Some(7));
assert_eq!(add(Some(3), None), None);
assert_eq!(add(None, Some(4)), None);
assert_eq!(add(add(Some(3), Some(4)), Some(5)), add(Some(3), add(Some(4), Some(5))));
}
#[test]
fn option_multiplicative_monoid() {
let one = <Option<u8> as Monoid<Multiplicative>>::identity();
assert_eq!(one, Some(1));
assert_eq!(mul(Some(3u8), Some(4)), Some(12));
assert_eq!(mul(Some(3), None), None);
assert_eq!(mul(None, Some(4)), None);
}
}