代数 - モノイド

積に関するモノイド \((X, \times, 1)\) を定義する.

Rust の i64 , f64 はそのまま乗算に関してモノイドになっている.

また, ユーザーが定義した型をモノイドにするためのマクロ monoid! を提供する.

// monoid マクロの使用例
monoid! {
    MyType ;
    one = MyType(1) ;
    mul(self, other) = { compute_multiplication(self, other) }
}

// 型パラメータを取る場合
monoid! {
    MyType<X> where [ X:Ord ] ;
    one = MyType(X::one) ;
    mul(self, other) = { compute_multiplication(self, other) }
}

monoid!product() , mul_assign() を自動で定義する.

/// Algebra - Def of Monoid (*, 1)
pub trait Monoid: std::ops::Mul<Output = Self> + std::iter::Product
where
    Self: std::marker::Sized,
{
    fn one() -> Self;
}

#[macro_export]
macro_rules! monoid {
    (
        $type:ty where [ $( $params:tt )* ];
        one = $one:expr;
        mul($self:ident, $y:ident) = $code:block
        $(;)*
    ) => {
        impl<$($params)*> std::ops::Mul for $type {
            type Output = Self;
            fn mul($self, $y: Self) -> Self { $code }
        }
        impl<$($params)*> std::ops::MulAssign for $type where Self: Clone {
            fn mul_assign(&mut $self, $y: Self) {
                *$self = (*$self).clone() * $y;
            }
        }
        impl<$($params)*> std::iter::Product for $type {
            fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
                iter.fold(Self::one(), std::ops::Mul::mul)
            }
        }
        impl<$($params)*> Monoid for $type {
            fn one() -> Self { $one }
        }
    };
    (
        $type:ty;
        one = $one:expr;
        mul($self:ident, $y:ident) = $code:block
        $(;)*
    ) => {
        monoid! { $type where []; one = $one; mul($self, $y) = $code; }
    };
}

impl Monoid for i64 {
    fn one() -> Self {
        1
    }
}
impl Monoid for i128 {
    fn one() -> Self {
        1
    }
}
impl Monoid for f64 {
    fn one() -> Self {
        1.0
    }
}