jjzjj

C++11:lambda,柯里化(Currying)

coder 2023-11-17 原文

我有以下代码。你能向我解释它是如何工作的吗?

template<typename Function, typename... Arguments>
auto curry(Function func, Arguments... args) {
    return [=](auto... rest) {
        return func(args..., rest...);
    };
}

int main() {
    auto add = [](auto x, auto y) {
        return x + y;
    };
    auto add4 = curry(add, 4);
    std::cout << add4(3) << '\n'; //output: 7. (Ok)

}

最佳答案

首先,你要知道什么currying是,或者在您的问题中,这特别是 partial application 的情况(与 curry 相关,但略有不同)。

基本上就是减少一个具有一定数量参数的函数,用于创建另一个具有固定参数值的函数。

我以你为例,原函数是add(x,y)它有两个参数 x 和 y。您可以通过将 x 设置为 4 来减少函数的 arity add 并创建减少的函数 add4(y)

add4(y) = add(x,y) 其中 x = 4

现在这是如何在您的 C++ 代码中实现的?在的帮助下可变参数模板 , 可变参数函数 lambda 函数 .

Lambda functions从 C++11 开始使用 C++。本质上,它们是动态创建的匿名函数,可以存储在变量中。您创建 add作为 main() 中的 lambda :

auto add = [](auto x, auto y) {
 return x + y;
};

可以通过模式 [] (list-of-arguments) {function-body}; 识别 lambda

注意:[]不总是空的,参见“捕获变量”there ,我们稍后再谈。

现在 curry 函数的目的是采用这些 lambdas 函数之一 func和一定数量的值作为参数,并定义一个 新功能来自 分配 func 的第一个参数的值按顺序排列.

variadic template 允许“一定数量的参数”机制参数Arguments... args这允许使用任意数量的类型作为模板参数调用模板(只要它们被称为编译时)。所以在我们的例子中,传递的参数是 4,所以 Arguments... args将被 int 取代,以及 curry 的实例将接受一个 lambda 和一个 int 作为参数.

如果我们看curry的代码,我们看到它只是一个 lambda 函数本身,(它是一个 variadic function ,就像 printf() ),其唯一目的是连接在实例化模板时已经固定值的参数( args... )和那些其值作为参数传递给柯里化(Currying)函数( rest... )。

[=] 符号是 lambda 函数的特殊捕获,它允许使用函数体中的所有局部变量(这里允许使用 args)。

所以总结一下,这是您的主要功能中发生的事情:
  • 您创建了一个名为 add 的变量其中包含一个 lambda
    函数,取两个参数并将它们相加。
  • 当您调用 curry(add,4)您实例化 curry模板。
  • 第一个模板参数Functionadd 的类型(一个 lambda 取两个 int 并返回一个 int )
  • 第二个可变参数只包含一种类型:4 的类型, 即 int

  • 实例化 curry功能看起来像这样
    curry( (int,int)->(int) func, int arg){
        return [=](auto... rest) {return func(arg, rest...);};
    }
    

    请注意,您永远不会看到这些类型,因为 auto和模板类型推导。
  • 然后你用 func 调用这个实例= addarg = 4
  • 您将此实例化的结果存储在 add4 中现在是一个带一个参数的 lambda。然后您可以调用 add4以 3 作为参数( rest... 为 3),然后将调用 add(4,3)并返回 7。

  • 请注意,从技术上讲,您可以尝试调用 add4有多个参数,因为柯里化(Currying)函数是一个可变参数函数。编译器只有在调用 add 时发现它没有这些额外参数的位置时才会失败。 (见 here)

    关于C++11:lambda,柯里化(Currying),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39468955/

    有关C++11:lambda,柯里化(Currying)的更多相关文章

    1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

      我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

    2. ruby - 使用 `+=` 和 `send` 方法 - 2

      如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

    3. ruby - 安装libv8(3.11.8.13)出错,Bundler无法继续 - 2

      运行bundleinstall后出现此错误:Gem::Package::FormatError:nometadatafoundin/Users/jeanosorio/.rvm/gems/ruby-1.9.3-p286/cache/libv8-3.11.8.13-x86_64-darwin-12.gemAnerroroccurredwhileinstallinglibv8(3.11.8.13),andBundlercannotcontinue.Makesurethat`geminstalllibv8-v'3.11.8.13'`succeedsbeforebundling.我试试gemin

    4. ruby - 如何计算 Liquid 中的变量 +1 - 2

      我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

    5. arrays - Ruby 数组 += vs 推送 - 2

      我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

    6. ruby - 了解在 Ruby 中与 lambda 一起使用的 inject 行为 - 2

      我经常将预配置的lambda插入可枚举的方法中,例如“map”、“select”等。但是“注入(inject)”的行为似乎有所不同。例如与mult4=lambda{|item|item*4}然后(5..10).map&mult4给我[20,24,28,32,36,40]但是,如果我制作一个2参数lambda用于像这样的注入(inject),multL=lambda{|product,n|product*n}我想说(5..10).inject(2)&multL因为“inject”有一个可选的单个初始值参数,但这给了我......irb(main):027:0>(5..10).inject

    7. ruby - ri 有空文件 – Ubuntu 11.10, Ruby 1.9 - 2

      我正在运行Ubuntu11.10并像这样安装Ruby1.9:$sudoapt-getinstallruby1.9rubygems一切都运行良好,但ri似乎有空文档。ri告诉我文档是空的,我必须安装它们。我执行此操作是因为我读到它会有所帮助:$rdoc--all--ri现在,当我尝试打开任何文档时:$riArrayNothingknownaboutArray我搜索的其他所有内容都是一样的。 最佳答案 这个呢?apt-getinstallri1.8编辑或者试试这个:(非rvm)geminstallrdocrdoc-datardoc-da

    8. ruby - 当你有一个没有参数的 case 语句并且 when 子句是 lambda 时会发生什么? - 2

      这段代码没有像我预期的那样执行:casewhen->{false}then"why?"else"ThisiswhatIexpect"end#=>"why?"这也不是casewhen->(x){false}then"why?"else"ThisiswhatIexpect"end#=>"why?"第一个then子句在两种情况下都被执行,这意味着我提供给when子句的lambda没有被调用。我知道无论when子句的主题是什么,都应该调用大小写相等运算符===。我想知道当没有为case提供参数时,===的另一边会发生什么。我在想它可能是nil,但它不可能是:->{false}===nil#=>

    9. ruby - 如何将 lambda 传递给 Hash.each? - 2

      如何将lambda传递给hash.each,以便我可以重复使用一些代码?>h={a:'b'}>h.eachdo|key,value|end=>{:a=>"b"}>test=lambdado|key,value|puts"#{key}=#{value}"end>test.call('a','b')a=b>h.each&testArgumentError:wrongnumberofarguments(1for2)from(irb):1:in`blockinirb_binding'from(irb):5:in`each'from(irb):5from/Users/jstillwell/.rv

    10. += 的 Ruby 方法 - 2

      有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

    随机推荐