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

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

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

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

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

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

6 ответов

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

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

С другой стороны, 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

Написано на эрланге:

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)))

Написано на Хаскеле:

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};
}

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

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

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

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

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

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

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

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

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

Приведенные выше ответы на вопросы @Alpine в основном определяют, что такое функции первого класса, а также примеры. Но все же остается один вопрос, зачем использовать?

Я попытаюсь ответить на вопрос о преимуществах немного иначе в Scala, где функции первого класса используются в дальнейшем как функции более высокого порядка (map, flatMap), частично прикладные функции и каррирование:

  1. Как мы ориентируемся на декларативном программировании как часть обработки данных остаются в качестве детали реализации на карту, flatMap, и сосредоточилась больше на работу с каким фактическим логическим потоком. Вызывающий может указать, что следует делать, и оставить функции более высокого порядка для обработки фактического логического потока.

  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/9781449368814/ch05.html

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

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

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

Из Скалы

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

Читать:

Другие вопросы по тегам