Чтобы быть ясным, я не хардкорный пользователь внутренних органов Джулии.Далее следует ответ, разработанный для (надеюсь) интуитивного объяснения того, какие функции есть у Юлии для нехардкорного пользователя.Я действительно думаю, что этот (очень хороший) вопрос мог бы также получить пользу от более технического ответа, предоставленного одним из основных разработчиков языка.Кроме того, этот ответ длиннее, чем мне бы хотелось, но я использовал несколько примеров, чтобы попытаться сделать вещи максимально интуитивно понятными.
Как отмечалось в комментариях, function
сам по себе являетсязарезервированное ключевое слово и не является действительной функцией само по себе само по себе , и поэтому является ортогональным к фактическому вопросу.Этот ответ предназначен для вашего редактирования вопроса.
Поскольку Julia v0.6 +, Function
является абстрактным супертипом, во многом так же, как Number
является абстрактным супертипом.Все функции, например mean
, пользовательские функции и анонимные функции, являются подтипами Function
, так же как Float64
и Int
являются подтипами Number
.
Thisструктура является преднамеренной и имеет несколько преимуществ.
Во-первых, по причинам, которые я до конца не понимаю, структурирование функций таким образом было ключом к тому, чтобы позволить анонимным функциям в Julia запускаться так же быстро, как встроенные функции изBase
.См. здесь и здесь в качестве отправных точек, если вы хотите узнать больше об этом.
Во-вторых, поскольку каждая функция имеет свой собственный подтип, теперь вы можете отправлять определенныефункции.Например:
f1(f::T, x) where {T<:typeof(mean)} = f(x)
и:
f1(f::T, x) where {T<:typeof(sum)} = f(x) + 1
- это разные методы отправки для функции f1
Итак, учитывая все это, почему, например, typeof(sum)
возврат typeof(sum)
, особенно если учесть, что typeof(Float64)
возвращает DataType
?Проблема здесь в том, что, грубо говоря, с синтаксической точки зрения, sum
должен одновременно служить двум целям.Это должно быть как значение, например, 1.0
, хотя и то, которое используется для вызова функции sum
на некотором входе.Но это также должно быть имя типа, например Float64
.
Очевидно, что оно не может делать оба одновременно.Так что sum
ведет себя как значение.Вы можете написать f = sum ; f(randn(5))
, чтобы увидеть, как оно ведет себя как значение.Но нам также нужен какой-то способ представления типа sum
, который будет работать не только для sum
, но и для любой пользовательской функции и любой анонимной функции.Разработчики решили пойти с (возможно) самым простым вариантом, и тип sum
печатается буквально как typeof(sum)
, отсюда и поведение, которое вы наблюдаете.Точно так же, если я напишу f1(x) = x ; typeof(f1)
, это также вернет typeof(f1)
.
Анонимные функции немного сложнее, так как они не названы как таковые.Что мы должны сделать для typeof(x -> x^2)
?На самом деле происходит то, что при создании анонимной функции она сохраняется как временная глобальная переменная в модуле Main
, и ей присваивается число, которое служит ее типом для целей поиска.Поэтому, если вы напишите f = (x -> x^2)
, вы получите что-то вроде #3 (generic function with 1 method)
, а typeof(f)
вернет что-то вроде getfield(Main, Symbol("##3#4"))
, где вы увидите, что Symbol("##3#4")
- это временный тип этой анонимной функции, хранящейся в Main
.(побочным эффектом этого является то, что если вы напишите код, который будет произвольно генерировать одну и ту же анонимную функцию снова и снова, вы в конечном итоге переполните память, поскольку все они на самом деле хранятся как отдельные глобальные переменные своего собственного типа).
Относя все это обратно к супертипу Function
, вы заметите, что typeof(sum) <: Function
возвращает true
, показывая, что тип sum
, то есть typeof(sum)
, действительно является подтипом Function
.И обратите внимание также, что typeof(typeof(sum))
возвращает DataType
, почти так же, как typeof(typeof(1.0))
возвращает DataType
, что показывает, как sum
действительно ведет себя как значение.
Теперь, учитывая все, что я сказал, все примеры в вашем вопросе теперь имеют смысл. typeof(function)
и typeof(for)
возвращают ошибки, как они должны, так как function
и for
являются зарезервированным синтаксисом. typeof(typeof)
и typeof(in)
правильно возвращают (соответственно) typeof(typeof)
и typeof(in)
, поскольку typeof
и in
являются обеими функциями. Обратите внимание, что typeof(typeof(typeof))
возвращает DataType
.