Функция Julia, возвращающая анонимную функцию - PullRequest
5 голосов
/ 26 мая 2020

Я пытаюсь понять относительно простой фрагмент кода, но не могу понять, что происходит (я новичок ie Julia, пришедший из Python / Matlab).

function myfunc(number::Integer)
    double() = 2*number
    square() = number^2
    return _ -> (number, double, square)
end

Я понимаю, что myfunc возвращает анонимную функцию, которая не заботится о переданном ей значении. Так что эти случаи имеют для меня смысл:

julia> n4 = myfunc(4)
#9 (generic function with 1 method)

julia> n4(50)
(4, var"#double#10"{Int64}(4), var"#square#11"{Int64}(4))

В первой строке n4 относится к самой функции анонимной , тогда как во второй анонимная функция вызывается с параметром 50 и делает то, что должно: отбрасывает 50 и возвращает кортеж, содержащий данные, с которыми он был определен .

Я не понимаю, как я могу это сделать:

julia> n4.square
(::var"#square#11"{Int64}) (generic function with 1 method)

julia> n4.square()
16

Тот факт, что n4, который относится к анонимной функции, имеет дочерние объекты n4.number, n4.double, n4.square - это для меня сюрприз. Как n4 ведет себя, как если бы это была структура? Выполнение n4(*)[2](), чтобы вернуть 8 в качестве ответа, имеет смысл, но когда fieldnames(n4) терпит неудачу, что-то происходит за кулисами, и я не понимаю, как заставить n4.double() работать. Где / каков механизм, с помощью которого я могу использовать . после n4 для доступа к функциям / данным?

1 Ответ

6 голосов
/ 26 мая 2020

В Julia все общие c функции (то есть все обычные функции, определенные Julia) являются структурами. Любую структуру можно сделать вызываемой в Julia, поэтому по умолчанию обычная функция - это просто структура с нулевым полем (синглтон), сделанная вызываемой. Другими словами, выполнение

foo(x) = x+1

похоже на

struct Foo end
const foo = Foo()
(::Foo)(x) = x + 1

Это отлично работает для обычных функций, но для анонимных функций это может вызвать создание большое количество новых видов. Например, вы могли бы сделать: functions = [x -> x+i for i in 1:1000].

Вместо создания 1000 новых типов, каждый с новым значением i, Джулия здесь создает один тип, содержащий i в качестве поля и 1000 экземпляров.

В вашем случае вместо myfunc, возвращающего новый тип для каждого вызова и возвращающего одноэлементный экземпляр этого типа, он возвращает экземпляр типа с полями number, double и square.

Кроме того, вы можете полностью вызывать имена полей, вам просто нужно вызвать его по типу: fieldnames(typeof(myfunc(4))).

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

...