[ad_1]
std::transform
から <algorithm>
ヘッダ 範囲に適用され、それが範囲をファンクターとして使用することを「可能にする」ものです (圏論の意味で(¹))。 std::transform
はい、イテレータベースですが、 std::ranges::views::transform
はそうではなく、その署名は関数型言語の対応する関数の署名とほぼ一致します (2 つの引数の順序が異なるモジュロですが、これは大した問題ではありません)。
私が見たとき この質問 (そしてその過程で それに答える)、C++23 で導入されていることを知りました。 std::optional<T>::transform
、これにより std::optional
ファンクターも。
これらすべてのニュースは本当に私を興奮させますが、ファンクターは一般的なものであり、統一されたインターフェースを持っているといいだろうと思わずにはいられません。 transform
たとえば、Haskell の場合のように、任意のファンクター。
これは、オブジェクトに似ていると思います std::ranges::views::transform
(ほのめかしていない別の名前で ranges
) にすることができます カスタマイズポイント STL は範囲だけでなく、 std::optional
また、STL 内の他のファンクタに対しても、プログラマはユーザー定義クラス用にカスタマイズできます。
まったく同じように、C++23 でも導入されています。 std::optional<T>::and_then
、これは基本的にのモナドバインディングです std::optional
. 範囲のモナド結合を実装する同様の関数は知りませんが、C++20 の some_range | std::ranges::views::transform(f) | std::ranges::views::join
は本質的に のモナド束縛です some_range
と f
.
そして、これは、いくつかの一般的なインターフェースが存在する可能性があると私に思わせます。名前を付けます mbind
、任意のタイプでオプトインできます。 STL は、 std::optional
の観点からそれを実装することによって std::optional<T>::and_then
、 例えば。
言語がいつの日かそのような汎用性をサポートする可能性はありますか、または計画はありますか?
私は確かにいくつかの問題を見ることができます。 今日 std::ranges::views::transform(some_optional, some_func)
は無効なので、一部のコードは SFINAE 経由でそれに依存している可能性があります。 突然動作させると、コードが壊れます。
(¹) 言葉に関しては オペレーター、圏論で与えられた定義を参照します (以下も参照)。 これ)、「持つクラスのオブジェクト」の概念ではありません operator()
定義された”; 後者は標準のどこにも定義されていません そして言及さえされていません cppリファレンス、代わりに用語を使用します 関数オブジェクト 参照する
関数呼び出し演算子の左側で使用できるオブジェクト
6
範囲のモナド結合を実装する同様の関数は知りませんが、C++20 の
some_range | std::ranges::views::transform(f) | std::ranges::views::join
は本質的に のモナド束縛ですsome_range
とf
.
ranges::views::for_each
範囲のモナドバインド (読んだ)、そして私はそれを好む views::transform | views::join
range-v3 の (過去の?) 複雑さ/入力の問題が原因です。
Functor と Monad のジェネリック インターフェイスを取得するかどうかについて。 そのような汎用性がテンプレートを作成するライブラリ作成者にとって有用でない限り、私はそれを疑っています。 std::expiremental::future
もモナドです(そして、エグゼキュータもそうであると思います)ので、次のような一般的なアルゴリズムを書くことができます foldM
この 3 つのタイプについて説明します。 Erik Niebler が range-v3 で、すべてのパイプ演算子を手作業でコーディングすることを犠牲にして Functor/Monad ライブラリを作成できることを示したと思います。
#include <fp_extremist.hpp>
template <typename M> requires Monad<M>
auto func(M m)
{
return m
| fp::extremist::fmap([](auto a) { return ...; })
| fp::extremist::mbind([](auto b) { return ...; })
;
}
私が実際に可能だと思うのは、UFCS と |>
演算子を使用して、次の利点を得ることができます invocable |> east
構文とアルゴリズムにパイプする機能。 から バリーのブログ:
範囲アダプターはパイプ可能ですが、アルゴリズムはそうでないため、機能しません。 …
つまり、x |> f は以前と同様に f(x) として評価されますが、x |> f(y) は f(x, y) として評価されます。
PS c++ で Functor の定義を与えることは難しくありません。 <typename T> struct
提供する transform
.
PSS
編集: applicative の扱い方に気づきました。
Applicative<int> a, b, c;
auto out = a
| zip_transform(b, c
, [](int a, int b, int c){ return a + b + c; })
;
zip_transform
ジッパー付きだから a
、 b
、 c
に Applicative<std::tuple<int, int, int>>
そしてそれを変換します(考えてください optional
、 future
、 range
)。 部分的に適用された関数の Applicative をいつでも使用できますが、それには C++ のスタイルではない多数のネストされた関数が含まれ、上から下への読み取り順序が乱れます。
あなたが探している答えではありませんか? タグ付けされた他の質問を閲覧する c++ 関数型プログラミング モナド オペレーター c++23 また 自分の質問をする.
[ad_2]
Source link
“これにより、 std::optional もファンクターになります。「これはどうやって作るの?
optional
それは機能しますか?– カン・ファンウェイ
1 月 9 日 11:12
オプションの値を表すデータ型 は ファンクタ。 Haskell はそれに名前を付けます
Maybe
、C++ で名前を付けるstd::optional
. Haskell はそれがファンクターであることを実装することによってエンコードしますfmap
為にMaybe
秒。 C++ではこれがありますstd::optional<T>::transform
これは同じ目的を果たしますが、Haskell のものとの唯一の違いです。fmap
それは memebr 関数です。– エンリコ
1 月 9 日 11:20
これらの変更を採用することが不可能/難しいと思わせる技術的な理由はありますか?
– 平均値
1 月 9 日 11:38
@康煥魏はありません 断定的な意味で 曖昧さを解決する?
– エンリコ
1 月 9 日 11:59
@idmean、考えられる問題の1つについて言及しました。 一部のコードの非有効性に依存する SFINAE コードは機能しなくなります。
– エンリコ
1 月 9 日 13:32
| |
見せる 1 もっとコメント