对不起,如果问题不太清楚.我不确定用它来表达它的最佳方式(随意编辑!).我认为一个例子是最清楚的:
我试图定义一个基于Haskell definition的Monad概念.绑定运算符(>> =)要求A类型的Monad可以绑定到一个带有A的函数并返回一个B类型的Monad.可以根据value_type typedef定义A,但如何在我的概念中定义类型B?
template <typename M>
concept bool Monad()
{
return requires(M m, Function<_1, ValueType<M>> f) {
// (>>=) :: m a -> (a -> m b) -> m b
{ m >>= f } -> M
}
}
在上面的例子中,我在Function<>中用什么来代替_1?概念?
这也足以将调用f的结果限制为任何类型的Monad吗?
最佳答案 我认为你能做的最接近的是提供一个特定的功能,即A – >单子< B个并验证它做对了.为了防止无限递归,我们可以验证A – > M作品:
template <class M>
concept bool Monad()
{
return requires(M m) {
{ m >>= std::function<M(ValueType<M>)>{} } -> M;
};
}
这只是一个具体案例,但我不相信有可能验证A – >的一般情况.单子< X>因为概念检查仍然涉及特定表达式,您只能创建具有特定类型的特定表达式.
当然,我们可以提供多种此类要求.使用重新绑定元函数:
template <class M, class X>
struct rebind;
template <class M, class X>
using rebind_t = typename rebind<M, X>::type;
template <template <class...> class Z, class R, class X>
struct rebind<Z<R>, X> {
using type = Z<X>;
};
然后我们可以为返回各种类型的函数添加需求,比如它也适用于int:
template <class M>
concept bool Monad()
{
return requires(M m)
{
{ m >>= std::function<M(ValueType<M>)>{} } -> M;
{ m >>= std::function<rebind_t<M,int>(ValueType<M>)>{} } -> rebind_t<M,int>;
};
}
通过将其重构为自己的子概念可能会变得更容易:
template <class M, class R>
concept bool MonadBind()
{
return requires(M m) {
{ m >>= std::function<rebind_t<M,R>(ValueType<M>)>{} } -> rebind_t<M,R>;
};
}
template <class M>
concept bool Monad()
{
return requires(M m) {
requires MonadBind<M, ValueType<M>>();
requires MonadBind<M, int>();
};
}