Monads in C++ (函数编程)

本文探讨了Monad在C++中的应用,包括std::optional如何模仿Haskell的Maybe Monad,以及C++20中Extended futures如何作为Monad支持函数组合,增强现代C++的并发编程能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Monad在Haskell被熟知。Monads in C++ ?帖子的名字真奇怪。

但这并不奇怪。使用std :: optional C ++ 17可获得monad。Eric Niebler的范围库和扩展的期货也是monads。对于这两者,我们都可以期望在C ++ 20中实现。

Bjarne Stroustrup在2016年C ++会议上的“秘密闪电演讲”中介绍了Concepts Lite的一些概念,这些概念我们很可能会在C ++ 20中得到。还存在诸如ring和monad之类的数学概念。我的假设变得越来越现实。现代C ++将在未来得到加强。

std::optional

std :: optional受Haskell的Maybe Monad启发。std :: optional原本打算成为C ++ 14的一部分,代表可能有一个值的计算。

因此,查找算法或哈希表查询必须处理无法回答问题的事实。通常,在这种情况下,使用特殊值表示没有值的存在,即所谓的无结果。通常,我们使用空指针,空字符串特殊整数值的无结果。这种技术既昂贵又容易出错,因为您必须以特殊方式处理无结果。无结果与常规结果属于同一类型。std :: optional在没有结果的情况下没有值。

这是一个简短的例子。

// optional.cpp

#include <experimental/optional>
#include <iostream>
#include <vector>

std::experimental::optional<int> getFirst(const std::vector<int>& vec){
  if (!vec.empty()) return std::experimental::optional<int>(vec[0]);
  else return std::experimental::optional<int>();
}

int main(){
    
    std::vector<int> myVec{1, 2, 3};
    std::vector<int> myEmptyVec;
    
    auto myInt= getFirst(myVec);
    
    if (myInt){
        std::cout << "*myInt: "  << *myInt << std::endl;
        std::cout << "myInt.value(): " << myInt.value() << std::endl;
        std::cout << "myInt.value_or(2017):" << myInt.value_or(2017) << std::endl;
    }
    
    std::cout << std::endl;
    
    auto myEmptyInt= getFirst(myEmptyVec);
    
    if (!myEmptyInt){
        std::cout << "myEmptyInt.value_or(2017):" << myEmptyInt.value_or(2017) << std::endl;
    }
    
}
  • 结果:
    在这里插入图片描述
  • 分析:
    std :: optional当前在命名空间中为实验性。这将随C ++ 17改变。我在函数getFirst中使用std :: optional(第7行)。getFirst返回第一个元素(如果存在)(第8行)。如果没有,您将得到一个std :: optional <int>对象(第9行)。

    我在主函数中使用了两个vector。第17和27行中的getFirst调用返回std :: optiona对象。如果是myInt(第19行),则该对象具有一个值;如果是myEmptyInt(Zeile 29),则该对象没有值。

    现在,我可以显示myInt的值(第20-22行)。第22和30行中的方法value_or返回该值还是默认值,这是取决于std :: optional是否具有值。

Extended futures

现代c ++支持任务task。
在这里插入图片描述
任务是通过通道连接的成对的std :: promisestd :: future对象。两个通信端点可能存在于不同的线程中。std :: promise(发送方)将其值推送到std :: future(接收方)正在等待的通道中。发送者可以将值,通知或异常推送到通道中。我写了一些关于任务的文章。详细信息如下:Tasks

创建promise的最简单方法是使用函数std :: asyncstd :: async的行为类似于异步函数调用。

int a= 2000
int b= 11;
std::future<int> sum= std::async([=]{ return a+b; });
std::cout << sum.get() << std::endl;

调用·std :: async·执行更多操作。首先,它创建了通信端点的promisefuture。第二,它通过一个通道将它们连接起来。lambda函数[=] {return a + b;}是promise的工作包。它从其定义的上下文中捕获参数a和b。C ++运行时决定promise将在相同或不同的线程中运行。决定的标准可能是工作包的大小,系统的负载或内核数。

future会调用sum.get()promise中获取值。您只能调用一次sum.get()。如果promise没有完成,则get调用将阻塞。

Tasks提供了类似且更安全的线程处理方式,因为它们没有必须保护的共享状态。因此,race conditions是不可能的,死锁更为罕见。

但是,C ++ 11实现的futures具有很大的缺点。 std :: future对象的组成是不可能的。这对于C ++ 20的 Extended futures将不成立。

下表显示了 Extended futures的功能。

在这里插入图片描述
以下是cpp提案n3721的一些代码片段。

future<int> f1= async([]() {return 123;});

future<string> f2 = f1.then([](future<int> f) {
     return f.get().to_string(); 
});

future<int> futures[] = {async([]() { return intResult(125); }), 
                         async([]() { return intResult(456); })};

future<vector<future<int>>> any_f = when_any(begin(futures), end(futures));


future<int> futures[] = {async([]() { return intResult(125); }), 
                         async([]() { return intResult(456); })};

future<vector<future<int>>> all_f = when_all(begin(futures), end(futures));

第3行中的future f2准备好了。您可以 延长 futures 链条:f1.then(...).then(...).then(...).

如果when_all futures已准备就绪,则第10行中的futures any_f将准备就绪。相反,如果 when_all准备就绪,第16行的future all_f则已准备就绪。

一个问题仍然没有得到回答。函数编程的未来有哪些共同点?A lot! **The extended futures are a monad.**我在Pure Functions /纯函数一文中解释了monad的概念。 monad的关键思想是monad将简单类型封装为丰富类型,并支持这些丰富类型上的函数组合。

因此,monad需要将简单类型提升为丰富类型的功能。另外,一个monad需要一个函数来使它们能够对丰富类型进行组合。这是函数make_ready_futurethenfuture <future <T >>的工作。 make_ready_future将简单类型映射为扩展类型,一个所谓的一元价值。该函数称为identity,在Haskell中具有返回名称。 thenfuture <future <T >>这两个函数等效于Haskell中的bind运算符。bind运算符的工作是将一个monadic value转换成另一个monadic valuebindmonad中的函数组成。

如果您想了解详细信息,则应该阅读Bartosz Milelweski的精彩博客并观看他的视频: “C++17: I See a Monad in Your Future!”。

翻译来源: https://www.modernescpp.com/index.php/monads-in-c

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值