Что такое гражданская функция первого класса? - PullRequest
42 голосов
/ 03 марта 2011

Что такое функция гражданина первого класса?

Поддерживает ли Java функцию гражданина первого класса?

Редактировать:
Как упоминается в Wikepedia

Функции первого класса необходимы для стиля функционального программирования.

Есть ли какое-либо другое использование функций первого класса?

Ответы [ 6 ]

49 голосов
/ 03 марта 2011

Язык, который считает процедуры «первоклассными» , позволяет передавать функции так же, как и любое другое значение .

Языки, такие как Java 7 (и ранее) и «своего рода» C имеют такую ​​возможность: C позволяет передавать указатели на функции, но вы не можете динамически определять функцию в этих языках и внезапно передавать ее в другое место.Java до версии 8 может имитировать в определенной степени это с анонимными классами, но технически не имеет функций первого класса.

С другой стороны, C ++, D, C #,Visual Basic .NET, Java 8+ и функциональные языки (такие как Scheme и Haskell) do позволяют передавать функции как переменные.Например, приведенный ниже код возвращает функцию, которая добавляет 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};
}

(Кстати, «лямбда» - это просто функция без имени. Лямбды поддерживаются только в языках, которые поддерживают первоклассные функции.)

3 голосов
/ 03 марта 2011

Функция первого класса может быть передана. Типичным примером является функция карты. Вот пример в 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.

1 голос
/ 13 ноября 2015

Рассмотрим пример парадигмы функционального программирования, в которой функции являются первоклассными гражданами.Когда мы говорим, что функции являются гражданами первого класса, мы можем выполнять следующие функции с помощью функции ...

  • Функция может быть назначена переменной
  • Функция может быть сохранена вструктура данных
  • Функция может передаваться в качестве аргумента другим функциям
  • Функция может быть возвращена из функций

В функциональных языках программирования возможноделать вышеупомянутые вещи.

Теперь давайте попробуем ответить на вопрос, поддерживает ли java функции гражданина первого класса (или) нет.

В java методы эквивалентны функциям.Невозможно сделать что-либо из перечисленного выше с помощью методов.Но все вышеперечисленное возможно с объектами Java.Итак, объекты являются первоклассными гражданами в Java.Следует признать, что java8 поддерживает передачу методов (точнее, поведения методов) в другие методы с использованием функциональных интерфейсов и лямбда-выражений.Но это не означает, что в Java есть функции граждан первого класса.

Возможность выполнять такие вещи, как передача функций, возврат функций из функций, очень мощная и полезная.Это потому, что это позволяет нам передавать поведение, а не только данные.

1 голос
/ 03 марта 2011

Определение из Википедии довольно хорошо - это функция, которую можно передавать, как и любой другой фрагмент данных. Java не поддерживает их. Ближайшие объекты - Runnable и Callable.

0 голосов
/ 03 марта 2011

Нет, вы не можете назначить метод переменной или передать его в качестве аргумента, например, другому методу.

Вместо этого вы можете использовать интерфейсы, чтобы обернуть предполагаемое поведение, или рефлексию, чтобы переопределить методы.

0 голосов
/ 03 марта 2011

Функции являются гражданами первого класса, то есть вы можете передавать функции в любом месте, как если бы это была переменная.

Из 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. Гражданин первого класса - это тот, кого можно пропустить куда угодно. Параллельно с первоклассным гражданином страны разрешено почти везде.

Читайте:

...