1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
use std::{
    iter::Sum,
    ops::{Add, Neg},
};

use monoid::{Associative, BinaryOp, Commutative, Identity, Recip};

#[derive(Clone, Debug)]
pub struct OpAdd<T>(std::marker::PhantomData<fn(&T) -> T>);

impl<T> Default for OpAdd<T> {
    fn default() -> Self { Self(std::marker::PhantomData) }
}

impl<T> BinaryOp for OpAdd<T>
where
    for<'a> &'a T: Add<&'a T, Output = T>,
{
    type Set = T;
    fn op(&self, lhs: &T, rhs: &T) -> T { lhs + rhs }
}

impl<T> Identity for OpAdd<T>
where
    for<'a> &'a T: Add<&'a T, Output = T>,
    T: for<'a> Sum<&'a T>,
{
    fn id(&self) -> T { None.into_iter().sum() }
}

impl<T> Recip for OpAdd<T>
where
    for<'a> &'a T: Add<&'a T, Output = T> + Neg<Output = T>,
    T: for<'a> Sum<&'a T>,
{
    fn recip(&self, elt: &T) -> T { elt.neg() }
}

impl<T> Associative for OpAdd<T> where for<'a> &'a T: Add<&'a T, Output = T> {}
impl<T> Commutative for OpAdd<T> where for<'a> &'a T: Add<&'a T, Output = T> {}

#[test]
fn sanity_check() {
    let op_add: OpAdd<i32> = Default::default();
    assert_eq!(op_add.op(&1, &2), 3);
    assert_eq!(op_add.id(), 0);
    assert_eq!(op_add.recip(&1), -1);
}