簡體   English   中英

std::foo::transform 有一天會支持任何函子嗎?

[英]Could std::foo::transform one day support any functor?

<algorithm> header 中的std::transform適用於范圍,它“使”我們能夠使用范圍作為它們的函子(在范疇論的意義上(¹))。 std::transform是基於迭代器的,是的,但std::ranges::views::transform不是,它的簽名與函數式語言中相應函數的簽名非常匹配,以兩個 arguments 的不同順序為模。

當我看到這個問題(並在回答它的過程中)時,我了解到 C++23 引入了std::optional<T>::transform ,這使得std::optional也成為一個仿函數。

所有這些消息確實讓我興奮,但我不禁認為函子是通用的,如果有一個統一的接口來transform任何函子,那就太好了,例如 Haskell 中的情況。

這讓我認為 object 類似於std::ranges::views::transform (具有不同的名稱不暗示ranges )可以作為定制點,STL 不僅可以為范圍定制,還可以為std::optional和 STL 中的任何其他仿函數,而程序員可以為他們的用戶定義的類定制它。

非常相似,C++23 也引入了std::optional<T>::and_then ,它基本上是std::optional的一元綁定。 我不知道有任何類似的 function 實現了范圍的單子綁定,但是 C++20 的some_range | std::ranges::views::transform(f) | std::ranges::views::join some_range | std::ranges::views::transform(f) | std::ranges::views::join some_range | std::ranges::views::transform(f) | std::ranges::views::join本質上是some_rangef的一元綁定。

這讓我覺得可能有一些通用接口,命名為mbind ,可以選擇任何類型。 例如,STL 將通過std::optional<T>::and_then實現它來選擇std::optional ::optional 。

有沒有機會,或者有沒有計划有一天該語言會支持這種通用性?


我當然可以看到一些問題。 今天std::ranges::views::transform(some_optional, some_func)是無效的,所以一些代碼可能通過 SFINAE 依賴它。 讓它突然工作會破壞代碼。


(¹)關於函子這個詞,我指的是范疇論中給出的定義(另請參見this ),而不是“定義了operator()的 class 的對象”的概念; 后者在標准中的任何地方都沒有定義,甚至在cppreference中也沒有提到,而是使用術語FunctionObject來指代

可以在 function 呼叫運算符左側使用的 object

我不知道有任何類似的 function 實現了范圍的單子綁定,但是 C++20 的some_range | std::ranges::views::transform(f) | std::ranges::views::join some_range | std::ranges::views::transform(f) | std::ranges::views::join some_range | std::ranges::views::transform(f) | std::ranges::views::join本質上是some_rangef的一元綁定。

ranges::views::for_each是范圍( read )的一元綁定,我更喜歡它而不是views::transform | views::join views::transform | views::join由於(過去?)range-v3 的復雜性/打字問題。

至於你是否會得到 Functor 和 Monad 的通用接口。 我對此表示懷疑,除非這種通用性對編寫模板的庫作者有用。 std::expiremental::future也是一元的(我想 Executors 也是),因此可以在這三種類型上編寫諸如foldM類的通用算法。 我認為 Erik Niebler 已經用 range-v3 表明,可以編寫一個 Functor/Monad 庫,但要以手動編碼每個 pipe 運算符為代價,即

#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語法的好處以及 pipe 到算法的能力。 來自巴里的博客

它不起作用,因為雖然范圍適配器是可管道的,但算法不是。 ...

也就是說,x |> f 仍然像以前一樣評估為 f(x)……但 x |> f(y) 評估為 f(x, y)。

PS 在 c++: <typename T> struct that provides transform中給出 Functor 的定義並不難。 PSS 也不清楚如何處理應用程序。 你想寫類似的東西

auto out = std::optional{1}
    , std::optional{1}
    | fp::extremist::app([](auto a, auto b){...})
    ;

並將其轉換為

auto out = [](auto a){ return [](auto b) {...}; }
    | fp::extremist::fmap(std::optional{1})
    | fp::extremist::app(std::optional{1})
    ;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM