【问题标题】:What is a first-class-citizen function?什么是一等公民功能?
【发布时间】:2011-07-07 21:02:35
【问题描述】:

什么是一等公民函数?

Java 是否支持一等公民功能?

编辑:
正如Wikepedia 中提到的那样

一流的功能是必需品 对于函数式编程风格。

头等函数还有其他用途吗?

【问题讨论】:

标签: java first-class-functions uses


【解决方案1】:

一种将过程视为“一流”的语言允许像任何其他值一样传递函数

Java 7(及更早版本)和“某种”C 语言具有这种能力:C 允许传递函数指针,但您不能在这些语言中动态定义函数并突然将其传递到其他地方。版本 8 之前的 Java 可以在一定程度上使用匿名类模拟这一点,但从技术上讲,它没有一流的功能。

另一方面,C++、D、C#、Visual Basic .NET、Java 8+ 和函数式语言(如 Scheme 和 Haskell)确实允许您传递变量等函数。例如,下面的代码返回一个将addend添加到其输入的函数:

写在 D 中:

int delegate(int) makeAdder(int addend) //Returns a function
{
    return delegate int(int x) //Long way
    {
        return x + addend; //Notice that addend came from _outside_ the function
    };

    return (int x) { return x + addend; }; //Short way

    return x => addend + x; //Super-short way, introduced in D 2.058
}

用 C# 编写:

Func<int, int> MakeAdder(int addend) //Returns a function
{
    return delegate(int x) //The long way. Note: Return type is implicitly 'int'
    {
        return x + addend;
    };

    return x => x + addend; //Short way: x "goes to" (x + addend); inferred types
}

用 C++ 编写:

#include <functional>

std::function<int(int)> make_adder(int addend)
{
    return [=](int x)
    {
        return addend + x;
    };
}

用 Scala 编写:

def makeAdder(addend: Int) = (x: Int) => addend + x

用 Python 编写:

def make_adder(addend):
    def f(x):
        return addend + x
    return f
    # or...
    return lambda x: addend + x

用 Erlang 编写:

make_adder(Addend) ->
    fun(X) -> Addend + X end.

用 JavaScript 编写:

function makeAdder(addend) {
    return function(x) {
        return addend + x;
    };
}

用 JavaScript 编写(ES2015 箭头函数语法):

const makeAdder = addend => x => addend + x;

写在方案中:

(define (makeAdder addend)
  (lambda (x)
    (+ x addend)))

用 Haskell 编写:

makeAdder :: Int -> (Int -> Int)
makeAdder addend = \x -> addend + x

用 Visual Basic 2008 编写:

Function MakeAdder(addend As Integer) As Func(Of Integer, Integer)
    Return Function(x) (x + addend)
End Function

用 Swift 编写(详细实现和简写实现):

func makeAdder(append: Int) -> (x: Int) -> Int {
    return { (x: Int) -> Int in
        return x + append
    };
}

func makeAdder(append: Int) -> (Int) -> Int {
    return {$0 + append};
}

(顺便说一句,“lambda”只是一个没有名称的函数。Lambda 仅在支持一流函数的语言中受支持。)

【讨论】:

  • 在 C++ 中可以使用模板函数对象:boost.org/doc/libs/1_46_0/libs/spirit/phoenix/doc/html/…
  • 它们不是函数,它们是函数对象。它们的行为相似,但它们不像 C# 或 D 中的 lambda,与具有 lambda 的语言相比,制作它们是一个巨大的痛苦,因为你必须声明一个全新的类,等等。
  • 无状态函子和函数之间没有区别。看看凤凰,你会感到惊讶
  • @aaa:是的,因为您的方法必须明确接受与普通函数指针不同的数据类型。相比之下,在 C# 中,您始终可以接受 Func&lt;int, int&gt;,无论该函数是 lambda 还是常规函数——函数指针和 lambda 的表示方式相同。
  • 我不关注你,明确地必须接受不同的数据类型?
【解决方案2】:

让我们考虑函数式编程范例的示例,其中函数是一等公民。当我们说函数是一等公民时,我们可以用函数做以下事情......

  • 函数可以赋值给变量
  • 函数可以存储在数据结构中
  • 函数可以作为参数传递给其他函数
  • 函数可以从函数中返回

在函数式编程语言中,可以做上述事情。

现在,让我们尝试回答这个问题,java 是否支持(或)一等公民函数。

在java中,方法等价于函数。无法使用方法执行上述任何操作。但是以上所有这些对于 java 对象都是可能的。所以,objects是java中的一等公民。诚然,java8 支持使用函数式接口和 lambda 表达式将方法(准确地说是方法行为)传递给其他方法。但这并不意味着 java 具有一等公民的功能。

上述的能力,比如传递函数,从函数返回函数是非常强大和有用的。这是因为,它允许我们传递行为而不仅仅是数据。

【讨论】:

    【解决方案3】:

    可以传递一流的函数。一个典型的例子是地图功能。这是 Scala 中的一个示例,它对列表的元素进行平方:

    val square = (x:Int) => x*x
    
    val squaredList = List(1,2,3,4).map(square _)
    //--> List(1,4,9,16)
    

    square 函数在这里是 map 方法的一个参数,它将它应用于每个元素。如果你想在 Java 中做这样的事情,你必须使用封装在类中的方法,如下所示:

    interface F<A,B>{ B apply(A a); }
    
    static <A,B> List<B> map(List<A> list, F<A,B> f) {
      List<B> result = new ArrayList<B>();
      for(A a:list) result.add(f.apply(a));
      return result;   
    }
    
    //we have to "wrap" the squaring operation in a class in order to make it a function
    F<Integer,Integer> square = new F<Integer,Integer>(){ 
      Integer apply(Integer a) { return a*a; }
    }
    
    List<Integer> ints = Arrays.<Integer>asList(1,2,3,4);
    List<Integer> squares = map(ints, square);
    

    看看这个,您可以看到您可以在 Java 中以某种方式完成相同的任务,但开销更大,并且没有语言的“本机”支持,而是使用解决方法(包装类)。所以Java不支持一等函数,但可以“模拟”它们。

    希望 Java 8 将支持一流的功能。如果您想现在获得一些支持,请查看http://functionaljava.org/http://functionalj.sourceforge.net/,或查看Scala 语言。

    【讨论】:

      【解决方案4】:

      Wikipedia definition 非常好——它是一个可以像任何其他数据一样传递的函数。 Java 确实支持它们。最接近的是 RunnableCallable 对象。

      【讨论】:

        【解决方案5】:

        @Alpine 问题的上述答案主要是定义什么是 First Class Functions 以及示例。但是,仍然存在一个问题,为什么要使用?

        我将尝试以稍微不同的方式回答 Scala 中的好处,其中一等函数被进一步用作高阶函数(map、flatMap)、部分应用函数和柯里化:

        1. 由于我们专注于声明式编程,处理数据的如何部分作为实现细节留给map、flatMap,并更多地关注处理what 实际的逻辑流程。 调用者可以指定应该做什么,让高阶函数来处理实际的逻辑流程。

        2. 部分应用函数和柯里化:如果您想重用函数调用并保留一些参数以避免再次输入它们怎么办?

        部分应用函数示例:

        def factorOf(x: Int, y: Int) = y % x == 0
        val multipleOf3 = factorOf(3, _: Int)
        val y = multipleOf3(78)
        

        柯里化例子:

        def factorOf(x: Int)(y: Int) = y % x == 0
        val isEven = factorOf(2) _
        val z = isEven(32)
        

        以上示例向您展示了如何通过不传递所有参数并保持代码DRY原则来重用一流函数的部分。 这些是使用一流函数的一些好处

        更多详情参考:https://www.oreilly.com/library/view/learning-scala

        【讨论】:

          【解决方案6】:

          不,例如,您不能将方法分配给变量或将其作为参数传递给另一个方法。

          相反,您可以使用接口来包装预期的行为,或使用反射来具体化方法。

          【讨论】:

          • 如何使用接口包装函数?
          【解决方案7】:

          函数是一等公民意味着您可以将函数传递到任何地方,就好像它是一个变量一样。

          来自 Scala

          def isOdd(in: Int) = in % 2 == 1
          val n = (1 to 10).toList
          n.filter(isOdd)
          
          see here: isOdd is a function. passed as if it's a variale.
          

          Objects 是 Java 中的一等公民。 一等公民是可以在任何地方通过的。类似的是,国家的一等公民几乎在任何地方都被允许。

          阅读:

          【讨论】:

            猜你喜欢
            • 2015-08-10
            • 2015-08-21
            • 1970-01-01
            • 2015-09-18
            • 1970-01-01
            • 2019-02-03
            • 1970-01-01
            • 1970-01-01
            • 2014-11-03
            相关资源
            最近更新 更多