Ответ 1
Это означает, что функции могут передаваться так же, как целые числа, последовательности и т.д.
Пример (хотя не Scala):
>>> def add2(x):
... return x + 2
...
>>> map(add2, [1, 2, 3])
[3, 4, 5]
Может кто-нибудь ясно объяснить это с помощью хорошего примера. Я столкнулся с этим утверждением в Scala, объясняя функциональное программирование.
Это означает, что функции могут передаваться так же, как целые числа, последовательности и т.д.
Пример (хотя не Scala):
>>> def add2(x):
... return x + 2
...
>>> map(add2, [1, 2, 3])
[3, 4, 5]
Быть "первоклассным" не является формально определенным понятием, но обычно это означает, что объект имеет три свойства:
Он может использоваться без ограничений везде, где могут быть "обычные" значения, т.е. переданы и возвращены из функций, помещены в контейнеры и т.д.
Он может быть построен без ограничений, где бы ни были "обычные" значения, т.е. локально, в выражении и т.д.
Его можно ввести так же, как "обычные" значения, т.е. существует тип, назначенный такой сущности, и он может быть свободно составлен с другими типами.
Для функций, (2), в частности, подразумевается, что локальная функция может использовать все имена в области видимости, т.е. у вас есть лексические замыкания. Он также часто имеет анонимную форму для построения (например, анонимные функции), но это не является строго обязательным (например, если язык имеет достаточно общие let-выражения). Точка (3) тривиально верна в нетипизированных языках.
Итак, вы понимаете, почему функции в Scala (и в функциональных языках) называются первоклассными. Вот несколько других примеров.
Функции в C/С++ не являются первоклассными. Хотя (1) и (3) возможно доступны через указатели функций, (2) не поддерживается для соответствующих функций. (То, что часто упускается из виду.)
Аналогично, массивы и структуры не являются первоклассными на земле C.
Классы в Scala не являются первоклассными. Вы можете определить и вложить их, но не, например, передайте их функции (только ее экземпляры). Существуют OO-языки с первоклассными классами, и на самом деле так называемое исчисление nuObj, которое сообщило о дизайне Scala, также позволяет это.
Первоклассные модули часто являются желательной функцией в ML-подобных языках. Они сложны, потому что они ведут к неразрешимой проверке типов. Некоторые ML-диалекты позволяют объединять модули в качестве первоклассных значений, но, возможно, это не делает модули первоклассными.
Любой язык программирования имеет базовый набор языковых функций, которые можно использовать для управления значениями, чтобы писать программы. Это такие вещи, как "передать значение функции", "привязать переменную к значению, а затем использовать переменную, как если бы это было значение" и т.д.
Всякий раз, когда вы видите, что утверждение о том, что язык имеет "X в качестве значений первого класса" или имеет "первый класс Xs", означает, что язык позволяет использовать эти базовые языковые функции на Xs. Другой способ сказать, что язык рассматривает Xs как значения.
Итак, вы можете заполнить пробел, чтобы сказать, что на каком-то языке есть поддержка использования определенного типа вещей в качестве значений. Например, Scala имеет функции первого класса (или функции - значения в Scala):
def plusOne(x : Int) = x + 1
val func : Int => Int = plusOne
println(func(1)) // prints 2
Python имеет первоклассные функции, но также имеет первоклассные классы (классы - значения в Python):
class Foo(object):
def __init__(self, thing):
self.thing = thing
cls = Foo
instance = cls(5)
print instance.thing # prints 5
print isinstance(thing, cls) # prints True
print isinstance(thing, Foo) # prints True
Это может показаться не очень большим, но основные функции любого языка программирования, говорящего о том, что вы можете делать со значениями, приводят к большему количеству вещей; если вы можете использовать функции как значения, то (как и любое другое значение) вы можете поместить их в контейнеры, получить неизвестные, вызывая другой код и т.д. и т.д.
Напротив, Java не имеет первоклассных функций. Вы не можете поместить функцию в переменную, передать одну или другую функцию или получить ее как возвращаемое значение функции. Функции не являются значениями в Java. Также у Java нет первоклассных классов.
Это означает, что функция является объектом. И так же, как и любой другой объект, он может быть назначен переменной или передан функции или что-то еще, что могут сделать объекты.
Например, вот переменная f
, которая содержит объект функции, который добавляет 1 к целому числу:
scala> val f = (n: Int) => n + 1
f: Int => Int = <function1> // Has type Int => Int; Int input, Int output
Он может передаваться как аргумент функции map
для List[Int]
:
scala> List(1,2,3).map(f) // map requires argument of type Int => Int
res0: List[Int] = List(2, 3, 4)
Это термин, взятый из чисто функциональных языков, таких как Haskell или Erlang, где функции являются гражданами первого класса. Это означает, что функции могут передаваться как аргументы другим функциям, а функции могут возвращать другие функции.
Поскольку функции являются гражданами первого класса, у нас есть тип функции - обозначается стрелкой. В haskel: (- > ) В skala: (= > )
Рассмотрим функцию отображения. Это функция, которая принимает функцию и список как свои аргументы и применяет данную функцию ко всем элементам списка:
в haskell:
map(\x->x+1)[1,2,3]
= [2,3,4]
в scala:
List(1,2,3) map (x => x + 1)
= [2,3,4]
(\x->x+1)
и (x => x + 1)
- это функции (обозначенные лямбда-выражениями), переданные функции отображения в качестве аргументов.
В функциональном программировании функции могут быть назначены переменным, переданы другим функциям в качестве параметров и возвращены как значения из других функций. Такие функции известны как функции первого класса. Функция более высокого порядка - это функция, которая принимает функцию в качестве аргумента или возвращает функцию.
Пример:
var increase = (x: Int) => x + 1