首页 > 解决方案 > 模板作为概念证据的部分应用?

问题描述

我有这个概念:

template<template<typename> typename M>
struct monad {
    // M<A> pure(A a)
    // M<B> flatMap(M<A> ma, std::function<M<B> (A)> f) // typename B = std::invoke_result_t<F&, A const&>

    static constexpr bool is_instance = false;
};

template<template<typename> typename M> concept MonadPure = requires(blackbox::A a, blackbox::B b) {
    { monad<M>::pure(a) } -> std::same_as<M<blackbox::A>>;
    { monad<M>::pure(b) } -> std::same_as<M<blackbox::B>>;
};

template<template<typename> typename M> concept MonadFlatMap = requires(M<blackbox::A> ma,
                                                                        blackbox::F<blackbox::A, M<blackbox::B>> f) {
    { monad<M>::flatMap(ma, f) } -> std::same_as<M<blackbox::B>>;
};

template<template<typename> typename M> concept Monad = monad<M>::is_instance && MonadPure<M> && MonadFlatMap<M>;

我想为变压器实施它的struct monad证据:StateT

template<template<typename> typename M, typename S, typename A> using StateT =
M<std::function<M<std::pair<S, A>>(S)>>;

由于以下内容无效:

template<template<typename> typename M, typename S>
requires Monad<M>
struct monad<template<typename A> StateT<M, S, A>> { // do stuff

我必须“部分申请” StateT

template<template<typename> typename M, typename S>
struct PartiallyAppliedStateT {
    template<typename A>
    struct _Apply {
        typedef StateT<M, S, A> type;
    };

    template<typename A>
    using Apply = typename _Apply<A>::type;
};

template<template<typename> typename M, typename S>
requires Monad<M>
struct monad<PartiallyAppliedStateT<M, S>::Apply> { // do stuff

然而,这给我留下了一个错误:

error: type/value mismatch at argument 1 in template parameter list for 'template<template<class> class M> struct monad'
   57 |     struct monad<PartiallyAppliedStateT<M, S>::Apply> {
      |                                                     ^
note:   expected a class template, got 'PartiallyAppliedStateT<M, S>::Apply'

我怎样才能使部分应用程序 a class,就像我认为 G++ 要求的那样?还是有更好的方法来制作StateT单子?

G++ 版本 10.1.0 与-std=c++20.


更正monad定义后:

template<template<typename> typename M, typename S>
requires Monad<M>
struct monad<PartiallyAppliedStateT<M, S>::template Apply> {

我可以这样描述一个函数:

template<template<typename> typename M>
requires Monad<M>
StateT<M, long, long> nextLong() {
    return monad<M>::pure([](long seed) {
        long next = seed * 6364136223846793005L + 1442695040888963407L;
        return monad<M>::pure(std::make_pair(next, seed));
    });
}

这表示从线性同余生成器获得输出。如果我们对 采取以下定义Id

template<typename A> using Id = A;

Id'spure只是返回传入的值,并且flatMap只是将函数应用于该值。那么下面的定义应该是有效的:

StateT<Id, long, long> doubleXor = monad<PartiallyAppliedStateT<Id, long>::template Apply>::flatMap(nextLong<Id>(), [](long value1) {
    return monad<PartiallyAppliedStateT<Id, long>::template Apply>::flatMap(nextLong<Id>(), [value1](long value2) {
        return monad<PartiallyAppliedStateT<Id, long>::template Apply>::pure(value1 ^ value2);
    });
});

该值doubleXor表示将 LCG 的种子推进两次然后对两个输出进行异或的操作。但是编译器找不到我们上面具体定义的实例,只能找到没有定义方法monad的默认实例:monad

In function 'long int doThing()':
error: 'flatMap' is not a member of 'monad<PartiallyAppliedStateT<Id, long int>::Apply>'
   95 |     StateT<Id, long, long> doubleXor = monad<PartiallyAppliedStateT<Id, long>::template Apply>::flatMap(nextLong<Id>(), [](long value1) {
      |                                                                                                 ^~~~~~~
In lambda function:
error: 'flatMap' is not a member of 'monad<PartiallyAppliedStateT<Id, long int>::Apply>'
   96 |         return monad<PartiallyAppliedStateT<Id, long>::template Apply>::flatMap(nextLong<Id>(), [value1](long value2) {
      |                                                                         ^~~~~~~
In lambda function:
error: 'pure' is not a member of 'monad<PartiallyAppliedStateT<Id, long int>::Apply>'
   97 |             return monad<PartiallyAppliedStateT<Id, long>::template Apply>::pure(value1 ^ value2);
      |                                                                             ^~~~

标签: c++templatesc++20c++-concepts

解决方案


推荐阅读