首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >管理不同类型的形态射及其构图

管理不同类型的形态射及其构图
EN

Code Review用户
提问于 2018-11-30 00:58:14
回答 1查看 174关注 0票数 2

下面是我编写的一些代码,用于管理C++17中不同类型的态射及其组合。

如果你有任何关于实质性简化或改进的建议,或者如果我遗漏了什么,请告诉我。

最后有一个示例,它将多个不同的态射组合在一起,然后确认最后的结果可以用于constexpr上下文。

代码语言:javascript
复制
#include 
#include 
#include 

/// Extract the first argument type from a map.
template 
constexpr A0 firstArg (R(*)(A0, As...));

/** Set theoretic morphisms **/

template
struct Homomorphism {
    constexpr static T value(const S);
};

template
struct Monomorphism: Homomorphism {
    constexpr static T value(const S);
};

template
struct Epimorphism: Homomorphism {
    constexpr static T value(const S);
};

template
struct Endomorphism: Homomorphism {
    constexpr static S value(const S);
};

template
struct Isomorphism: Monomorphism, Epimorphism {
    constexpr static T value(const S);
};

template
struct Automorphism: Endomorphism, Isomorphism {
    constexpr static S value(const S);
};

template,
         typename T1 = std::decay_t()))>,
         typename T2 = std::decay_t,
         typename R  = std::decay_t()))>>
struct MonomorphismComposition: Monomorphism {
    static_assert(std::is_base_of_v, H1>);
    static_assert(std::is_base_of_v, H2>);
    static_assert(std::is_same_v);
    constexpr static R value(const S &s) {
        return H2::value(H1::value(s));
    }
};

template,
         typename T1 = std::decay_t()))>,
         typename T2 = std::decay_t,
         typename R  = std::decay_t()))>>
struct EpimorphismComposition: Epimorphism {
    static_assert(std::is_base_of_v, H1>);
    static_assert(std::is_base_of_v, H2>);
    static_assert(std::is_same_v);
    constexpr static R value(const S &s) {
        return H2::value(H1::value(s));
    }
};

template,
         typename T1 = std::decay_t()))>,
         typename T2 = std::decay_t,
         typename R  = std::decay_t()))>>
struct IsomorphismComposition: Isomorphism {
    static_assert(std::is_base_of_v, H1>);
    static_assert(std::is_base_of_v, H2>);
    static_assert(std::is_same_v);
    constexpr static R value(const S &s) {
        return H2::value(H1::value(s));
    }
};

template,
         typename T2 = std::decay_t,
         typename T  = std::enable_if_t, T1>>
struct EndomorphismComposition: Endomorphism {
    static_assert(std::is_base_of_v, H1>);
    static_assert(std::is_base_of_v, H2>);
    constexpr static T value(const T &s) {
        return H2::value(H1::value(s));
    }
};

template,
         typename T2 = std::decay_t,
         typename T  = std::enable_if_t, T1>>
struct AutomorphismComposition: Automorphism {
    static_assert(std::is_base_of_v, H1>);
    static_assert(std::is_base_of_v, H2>);
    constexpr static T value(const T &s) {
        return H2::value(H1::value(s));
    }
};

template,
         typename T1 = std::decay_t()))>,
         typename T2 = std::decay_t,
         typename R  = std::decay_t()))>>
struct HomomorphismComposition: Homomorphism {
    static_assert(std::is_base_of_v, H1>);
    static_assert(std::is_base_of_v, H2>);
    static_assert(std::is_same_v);
    constexpr static R value(const S &s) {
        return H2::value(H1::value(s));
    }
};

template
struct IdentityAutomorphism: Automorphism {
    constexpr static T value(const T &t) {
        return t;
    }
};

/** This is a monomorphism if the type of S is a subset of T, i.e. is convertible to T. **/
template
struct EmbeddingMonomorphism: Monomorphism {
    static_assert(std::is_convertible_v);
    constexpr static T value(const S &s) {
        return s;
    }
};

/*** EXAMPLE ***/

struct divby2: Automorphism { constexpr static double value(double d) { return d / 2; }};
struct embed_divby2: MonomorphismComposition, divby2> {};

struct squared: Monomorphism, Endomorphism { constexpr static int value(int i) { return i * i; } };
struct squared_embed_divby2: MonomorphismComposition {};

struct S {
    explicit constexpr S(int val): val{val} {};
    const int val;
};
struct s_to_int: Isomorphism { constexpr static int value(const S &s) { return s.val; } };

struct bighom: MonomorphismComposition {};
struct biggerhom: MonomorphismComposition> {};

constexpr auto sum() {
    double d = 0;
    for (int i = 0; i < 10; ++i)
        d += biggerhom::value(S{i});
    return d;
}

int main() {
    for (int i = 0; i < 10; ++i)
        std::cout << biggerhom::value(S{i}) << '\n';

    constexpr double d = sum();
    std::cout << "Sum is: " << d << '\n';
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2018-11-30 11:16:26

我的印象是,这段代码是一个更大的设计的一部分,它的范围和意图我无法完全猜出来。对不起,如果我的审查在这方面似乎有点限制性或目光短浅。

通用设计

我的理解是,您希望在相当宽松的C++函数和类函数类型集上构建一个数学类型系统。这是一项崇高的事业,但我恐怕他们是如此不同的现实,它将结束在一个误解。

使用c++应用程序的定义:R(*)(A0, As...) (在firstArg签名中)。这将匹配一个函数指针,但是函数引用、lambdas、成员函数、函子、指向成员函数的指针都是合法的目标,它们不一定与此签名匹配。

还有函数重载的问题:如果foo有三个重载怎么办?R(*)(A0, As...)将匹配哪一种?(答案是没有,它根本不会编译)。

此外,与这种有力的简化相比,您还构建了一个复杂的继承树,它的语义对编译器是透明的,至少超出了参数和返回类型之间的身份:编译器将如何决定函数是否真的是一个单形?

我相信您最好使用一个更简单的设计,解偶联c++类型和数学类型,至少在一定程度上如此。

C++应用程序组合

这本身就已经是一个很难解决的问题,这取决于您想要对域进行多大的限制。但是,如果您只想接受将S value(T)作为接口公开的应用程序,这肯定会更容易。那么,我建议的是提供一个更简单的模板:

代码语言:javascript
复制
template 
struct Application {

    using result_type = R;
    using argument_type = A;
    
    template 
    Application(F f) : fn(f) {}

    R value(A) { return fn(a); } // no need to have it static now

    std::function fn;
};

然后,您可以将任何符合要求的类函数对象转换为兼容的Applicationauto square = Application([](auto n) { return n * n; };。现在验证应用程序组合非常简单:std::is_same (std::is_convertible也可能是一种选择)。

形态分类

我对这种无所不包的继承树有点怀疑。首先要注意的是,根据基类中的规范,简单继承不会限制派生类中的value。从endomorphism继承不会约束类公开参数类型和返回类型相同的value函数。虚拟函数会限制它,但坦率地说,多继承似乎是不必要的危险和复杂。

您可以做的是将这种类型的态射作为标记,然后用std::enable_if和std::conditional约束函数D21:

代码语言:javascript
复制
template 
struct Application {
    // ...
    using morphism_tag = Morphism;
    using result_type = std::conditional_t,
                                           std::enable_if_t, R>,
                                           R
                                          >;
    result_type value(argument_type);
    // ...
};

如果生成带有返回类型与参数类型不匹配的Application标记的Endomorphism,则代码将不会编译。

但是,我不确定它的可扩展性,也不确定我们能够执行哪些规则。

态合成

有了这个基础结构,您就可以更容易地按照以下思路组合态射:

代码语言:javascript
复制
template 
constexpr auto resulting_morphism(Application, Application) {
    if constexpr (std::is_base_of_v && std::is_base_of_v)
        return Monomorphism();
    else if constexpr ( /*...*/ )
    // ...
    else throw std::logical_error(); // throw in constexpr context simply won't compile
)

template 
constexpr auto compose(Application a1, Application a2) {
    return Application([](auto arg) {
        return a1(a2(arg));
        });
}
票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/208736

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档