だから私は GCC6 とその概念の実装で遊んでいて、Haskell Prelude が実験の良いソースになると考えました。Haskell のコア機能の 1 つは関数合成であり、これは私がすぐに取り組む必要があったものです。
できる限り Haskell の構文を模倣して、次の関数を作成しました。
template <typename F, typename G>
auto operator*(F f, G g)
{
return [f, g](auto... args) {
return f(g(args...));
}
}
これはうまく機能し、次のようなことができます。
auto add([](int a, int b) { return a + b; }
auto doubled([](int a) { return a * 2; }
auto add_then_double(doubled * add);
assert(add_then_double(2, 3) == 10);
幸いなことに、戻って関数の構成にいくつかの制約を適用することにしましたが、その遅延のためにすぐに問題にぶつかりました。
最初に私はこの概念を書きました:
template <typename F, typename Ret, typename... Args>
concept bool Function()
{
return requires(F f, Args ...args) {
{ f(args...) } -> Ret;
}
}
これは、 Andrew Sutton の origin github プロジェクトにある概念に基づいています。
それで、私は自分の元の機能に適用しようとしました。私が持っている問題は、G
どの引数が渡されるかを知らずに何が返されるかわからないため、G
制約することができず、どのパラメーターが与えられているかを知らずに何が返されるかがわからず、それがわからないことです。何が返ってくるかわかりません。G
F
G
呼び出し可能である限りFunction
、構成関数は戻り値を気にしないため、戻り値の型を気にしない新しい概念が必要であると確信しています。F
そして、パラメーターの型と G、したがって F を修正する内部ラムダに制約を課すことができると思いますが、これは、構成不可能な関数を構成でき、呼び出しサイトまでエラーが発生しないことを意味します。これは避けられますか?
多分このようなもの:
template <typename F, typename G>
auto operator*(F f, G g)
{
return [f, g](auto... args)
// is it even possible to constrain here?
requires FunctionAnyReturn<G, decltype(args)...>
&& FunctionAnyReturn<F, decltype(G(decltype(args)...))>
{
return f(g(args...));
}
}
これは私ができる最善のことですか (それができる場合でも)?