Skip to content

Instantly share code, notes, and snippets.

@wecing
Created May 3, 2015 07:10
Show Gist options
  • Save wecing/172ace00a4ea807215d4 to your computer and use it in GitHub Desktop.
Save wecing/172ace00a4ea807215d4 to your computer and use it in GitHub Desktop.
Sum and Product monoid in C++
#include <iostream>
#include <cstdlib>
#include <memory>
#include <vector>
#include <string>
template<typename M, typename T>
class SemiGroup {
protected:
T m_t;
public:
SemiGroup(T t) : m_t(t) {}
SemiGroup<M,T> mappend(SemiGroup<M,T> other);
T get() { return m_t; }
};
template<typename M, typename T>
class Monoid : public SemiGroup<M,T> {
public:
Monoid(T t) : SemiGroup<M,T>(t) {}
static Monoid<M,T> mzero;
};
class Sum {};
template<>
SemiGroup<Sum, int> SemiGroup<Sum, int>::mappend(SemiGroup<Sum, int> other) {
return SemiGroup<Sum, int>(m_t + other.m_t);
}
template<>
Monoid<Sum, int> Monoid<Sum, int>::mzero = Monoid<Sum, int>(0);
class Product {};
template<>
SemiGroup<Product, int> SemiGroup<Product, int>::mappend(SemiGroup<Product, int> other) {
return SemiGroup<Product, int>(m_t * other.m_t);
}
template<>
Monoid<Product, int> Monoid<Product, int>::mzero = Monoid<Product, int>(1);
template<typename M, typename T>
Monoid<M, T> mconcat(const std::vector<T> & vals) {
Monoid<M, T> r = Monoid<M, T>::mzero;
for (auto v : vals) {
r = Monoid<M, T>(r.mappend(v).get());
}
return r;
}
int main(void) {
std::vector<int> vals{3, 5};
std::cout << "Sum::mconcat [3,5] == "
<< mconcat<Sum,int>(vals).get()
<< std::endl;
std::cout << "Product::mconcat [3,5] == "
<< mconcat<Product,int>(vals).get()
<< std::endl;
return 0;
}
@darkfall
Copy link

darkfall commented May 3, 2015

#include <iostream>
#include <cstdlib>
#include <memory>
#include <vector>
#include <string>


struct Sum {};
struct Product {};

template<typename M, typename T>
struct MZero { };

template<typename T>
struct MZero<Sum, T> { enum { V = 0 }; };

template<typename T>
struct MZero<Product, T> { enum { V = 1 }; };

template<typename M, typename T>
struct MOp { static T Op(T v1, T v2); };

template<typename T>
struct MOp<Sum, T> { static inline T Op(T v1, T v2) { return v1 + v2; } };

template<typename T>
struct MOp<Product, T> { static inline T Op(T v1, T v2) { return v1 * v2; } };


template<typename M, typename T>
class SemiGroup {
protected:
    T m_t;

public:
    typedef SemiGroup<M, T> self_type;

    SemiGroup(T t) : m_t(t) {}

    self_type mappend(self_type other) const
    {
        return self_type(MOp<M, T>::Op(m_t, other.m_t));
    }

    T get() const { return m_t; }
};

template<typename M, typename T>
class Monoid : public SemiGroup<M,T> {
public:
    Monoid(T t) : SemiGroup<M,T>(t) {}
    static Monoid<M,T> mzero;
};

template<typename M, typename T>
Monoid<M, T> Monoid<M, T>::mzero = Monoid<M, T>(MZero<M, T>::V);

template<typename M, typename T, typename... Args>
Monoid<M, T> mconcat(const T& t, const Args&... args) {

    Monoid<M, T> n = Monoid<M, T>(Monoid<M, T>::mzero.mappend(t).mappend(args...).get());

    return n;
}

template<typename M, typename T, typename C>
Monoid<M, T> mconcatC(const C& vals) {
    Monoid<M, T> r = Monoid<M, T>::mzero;
    for (auto v : vals) {
        r = Monoid<M, T>(r.mappend(v).get());
    }
    return r;
}

int main(void) {
    std::cout << "Sum::mconcat [3,5] == "
              << mconcat<Sum>(3, 5).get()
              << std::endl;

    int v[] = {3, 5};
    std::cout << "Product::mconcat [3,5] == "
              << mconcatC<Product, int>(v).get()
              << std::endl;

    return 0;
}

@wecing
Copy link
Author

wecing commented May 3, 2015

(心悦诚服(但是你的写法比我的长啊))@darkfall

@darkfall
Copy link

darkfall commented May 3, 2015

(睡前意识模糊状态下的, 其实没啥卵区别, 除了variadic template可以传任意多个参数进去而不用构造list, 几个模板单独出来个人觉得扩展比较方便, 这样就不用偏特化你的类而是几个trait模板(不用在意那些细节( @wecing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment