zoukankan      html  css  js  c++  java
  • 函数工厂Curry的威力

    概述

    “完全”函数式编程 一文中,我们初步感受了函数式编程的力量:以非常简洁的代码,通过组合任何短小的简单函数,实现更加复杂功能的复合函数。

    有小伙伴可能会问: 既然函数是这么重要的原材料,那么从哪里可以获取这么多原材料呢 ?总不成,一个个去定义吧。别急,Curry 提供了批量生产函数的能力,—— 如果星云是恒星的工厂,那么,Curry 就是函数的工厂。

    本文将以 Groovy 为示例,讲解 Curry 的特性及能力。

    基础知识

    小伙伴都学过多元函数,比如 f(x,y) = x^2 + y ,当 y = 0 时,就变成 f(x) = x^2 平方函数; 当 x = 1 时,就变成 f(y) = 1+y 线性函数。 Curry ,通俗地说,就是将多变量的函数,通过逐个因变量赋值,从而批量生成函数的能力。

    如下代码所示: def closure = { x,y -> x^2 +y } 定义了一个二元函数 f(x,y) , rcurry(0) 即是将 y 赋值为 0 (右边的参数),这样就得到了一元函数 square(x) = x^2 ; curry(1) 即是将 x 赋值为 1 (默认是左边的参数),就得到了 linear(y) = 1+y 。 嗯,就是这么简单。

    class Basics {
    
        static void main(args) {
            def closure = { x,y -> x * x +y }
            def square = closure.rcurry(0)
    
            println((1..5).collect { square(it) })
    
            def linear = closure.curry(1)
            println((1..5).collect { linear(it) })
    
        }
    }
    

    输出结果:

    [1, 4, 9, 16, 25]
    [2, 3, 4, 5, 6]
    

    实际应用

    那么 Curry 有什么实际应用呢 ? 总不能只停留在数学的领域里。 实际上 Curry 的能力非常强大。我们来实现一个通用调用器。在实际工程中,常常需要调用具有相同参数的函数,或者对不同的对象进行相同的处理。

    假设有两个订单处理函数: cancel, complete ,有一个列表排序函数 sort:

       def static sort(list) {
            list.sort()
            return list
        }
    
        def static cancel(order) {
            println ("cancel: " + order.orderNo)
        }
    
        def static complete(order) {
            println ("complete: " + order.orderNo)
        }
    
    class OrderParam {
        def orderNo
        def shopId
    }
    

    可以定义一个二元函数 generalCaller ,可以对指定的参数对象 param 使用指定的 handler 进行处理。

    def generalCaller = { param, handler -> handler(param) }
    

    现在,来看怎么使用:

    第一种方式:指定参数对象。 可以构造一个订单对象,使用 Curry ,就得到了可以处理这个订单的函数处理器 orderProcessor, 然后就可以传入不同的订单处理器进行处理。this.&method 是 Groovy 对函数的引用。

    def orderProcessor = generalCaller.curry(new OrderParam(orderNo: 'E0001', shopId: 55))
    orderProcessor(this.&cancel)
    orderProcessor(this.&complete)
    

    第二种方式,指定处理器。 就得到了一个对参数进行排序的函数 sort(param) , 然后传入不同的可排序对象进行处理:

    def sorter = generalCaller.rcurry(this.&sort)
    println sorter([4,7,2,6,1,3])
    println sorter(["i", "have", "a", "dream"]) 
    

    是不是非常灵活 ? 在 “函数柯里化(Currying)示例” 一文中,使用 Curry 实现了一个简易的文件处理框架。

    小结

    Curry 可以将高维函数逐步降维,批量生成大量的低维函数。 如果有一个 N 维函数,思考下,通过 Curry ,可以生成多少个低维函数 ?Curry 结合函数式编程,蕴藏着惊人的潜力。

  • 相关阅读:
    Sum Root to Leaf Numbers 解答
    459. Repeated Substring Pattern
    71. Simplify Path
    89. Gray Code
    73. Set Matrix Zeroes
    297. Serialize and Deserialize Binary Tree
    449. Serialize and Deserialize BST
    451. Sort Characters By Frequency
    165. Compare Version Numbers
    447. Number of Boomerangs
  • 原文地址:https://www.cnblogs.com/lovesqcc/p/12178211.html
Copyright © 2011-2022 走看看