шаблоны — Cont Monad в переполнении стека

Я пытаюсь выразить монаду Haskell Cont в C ++ и запутался в переводе набора текста на C ++.

Мой текущий подход заключается в создании двух классов для операций bind и return. Они содержат тип значения A и тип возврата R,

template<typename _R, typename _A>
class Cont
{
public:
typedef _A A;
typedef _R R;

virtual R Run(const std::function<R(A)>& k) const=0;
};

template<typename M, typename F,
typename B = typename std::remove_pointer<typename std::result_of<F(typename M::A)>::type>::type,
typename R = typename B::R,
typename A = typename B::A>
class BindCont : public Cont<R, A>
{
M* m;
F f;
public:
explicit BindCont(M* m, const F& f) : m(m), f(f) { }

virtual R Run(const std::function<R(A)>& k) const
{
return m->Run([&](typename M::A x) { return f(x)->Run(k); });
}
};

template<typename A>
class ReturnCont : public Cont<A, A>
{
A x;
public:
explicit ReturnCont(A x) : x(x) { }

virtual A Run(const std::function<A(A)>& k) const
{
return k(x);
}
};

template<typename M, typename F>
BindCont<M, F>* Bind(M* m, const F& f) { return new BindCont<M, F>(m, f); }

template<typename A>
ReturnCont<A>* Return(A x) { return new ReturnCont<A>(x); }

Это работает для составления объектов одного типа, но понятно, что происходит сбой при преобразовании Bind в другой тип:

// This works as the resulting Cont is the same as the Cont being bound.
auto m1 = Bind(Return(4), [](int x)
{
return (x < 10 ? Return(10) : Return(x));
});

// This fails as when m is run in BindCont, it expects an int, not a const char*
// to be returned.
auto m2 = Bind(Return(4), [](int x)
{
return (x < 10 ? Return("abc") : Return("xyz"));
});

Другие попытки

Моя первая попытка опиралась только на A и определил тип возврата R из общего функтора в Run:

template<typename A>
class ReturnCont : public Cont<A>
{
A x;
public:
explicit ReturnCont(A x) : x(x) { }

template<typename K>
typename std::result_of<K(A)>::type Run(const K& k) const { return k(x); }
};

Однако это, хотя и решает проблему с реализацией bind, требует решения во время компиляции о том, какая реализация Cont использовать быть сделано во время выполнения, как общий Run интерфейс не может быть выражен на базовом классе Cont,


Вопросы

Исходя из исходного кода, у меня есть два вопроса:

  • Типы R а также A в BindCont правильный? Я попытался добавить явное R а также A типы для обоих BindCont а также ReturnCont но не могу понять их правильно.
  • Как может BindCont::Run быть реализован, чтобы соединить вычисления разных типов вместе?

Я должен также отметить, что имея Run вернуть void работает в оригинальном случае и позволяет правильно реализовать связывание. Это может быть приемлемо для определенных случаев, но предпочтительнее иметь возвращаемое значение.

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …