2016-04-12 16 views
4

ご質問があまりにも明確でない場合は申し訳ありません。私はそれをフレーズする最善の方法がわからない(自由に編集できる!)。私は一例が最も明確だと思う:C++の概念:それ自体がテンプレートである概念を定義できますか?

私はHaskell definitionに基づいてモナドの概念を定義しようとしています。バインド演算子(>>=)は、タイプAMonadを、Aを受け取り、タイプBMonadを返す関数にバインドする必要があります。 Avalue_type typedefの形で定義することはできますが、私のコンセプトにはタイプ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 
    } 
} 

は、私が機能<>コンセプトで _1の代わりに何を入れますか?

これは、fを呼び出す結果がどのタイプのモナドであるかを十分に制限していますか?

+1

='ここでのミスのように思えます。 C++では 'a >> = b >> = c'は' a >> =(b >> = c) 'として関連付けられ、ハスケルでは'(a >> = b)>> = c'として関連付けられます。 –

+0

ええ私は知っている:)明らかに生産価値のあるコードではない - ちょうど概念について少し学ぶための遊びを持っている –

答えて

1

固有のの機能をA --> Monad<B>に提供し、それが正しいことを確認することです。無限再帰を防止するために、私たちはA --> M機能するかどうかを確認することができます

template <class M> 
concept bool Monad() 
{ 
    return requires(M m) { 
     { m >>= std::function<M(ValueType<M>)>{} } -> M; 
    }; 
} 

これが唯一の特定のケースですが、私は一般的なケースを検証することが可能であるとは考えていないことからA --> Monad<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>; 
    }; 
} 

独自のサブにそのリファクタリングによって容易に得るかもしれません-concept: `演算子を使用して>>さておき、(AB)として

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>(); 
    }; 
}