Возможно ли получить возвращаемый тип функции Джулии в неоцененном контексте? - PullRequest
6 голосов
/ 10 октября 2019

Я хочу получить тип результата вызова функции в Julia без оценки функции и использовать этот тип. Желаемое использование выглядит примерно так:

foo(x::Int32) = x
foo(x::Float32) = x

y = 0.0f0
# Assert that y has the type of result of foo(Float32)
y::@resultof foo(Float32) # This apparently does not work in Julia

Хотя в приведенном выше случае я могу просто использовать y::typeof(foo(1.0f0)) с оценкой фиктивной переменной, в более сложных случаях инициализация фиктивной переменной может быть неудобной идорого. Например, я хочу использовать тип итератора, возвращаемый функцией eachline(filename::AbstractString; keep::Bool=false), но использование typeof действительно требует успешного открытия файла, что выглядит как перебор.

Из фона C ++, что яСпрашивается, есть ли в Джулии эквивалент std::result_of? Вопрос почти такой же, как этот , но язык - Юлия.


После некоторых исследований я вижу, что Юлия позволяет возвращать значения различных типов в одной функции, гдевывод типа выглядит очень сложно. Например,

foo(x::Int64) = x == 1 ? 1 : 1.0

Тип возвращаемого значения теперь может быть Int64 или Float64, в зависимости от входного значения. Тем не менее, в этом случае мне все еще интересно, есть ли какие-нибудь макро-трюки, которые могут сделать вывод, что тип возвращаемого значения равен Union{ Int64, Float64 }?


Подводя итог, я могу задать следующие вопросы:

  1. По сути, возможно ли получить возвращаемый тип функции, только указав типы аргументов в Julia?
  2. Если 1 невозможно, для функций, имеющих один детерминированный тип возвращаемого значения (как в первом примере), возможно ли получить возвращаемый тип без оценки?
  3. (Возможно, это не связано с тем, что я хочу, но я думаю, что это может улучшить мое понимание) Когда компилируются коды Джулии, известны ли типы возвращаемых функций? Или информация о типе определяется только во время выполнения?

1 Ответ

8 голосов
/ 10 октября 2019

1) Да, Base.return_types(foo, (Int64,)) вернет массив, содержащий тип возвращаемого вами значения, то есть Union{ Int64, Float64 } в данном случае. Если вы отбросите второй аргумент, кортеж, определяющий типы входных аргументов, вы получите все возможные типы возвращаемых значений.

Следует отметить, однако, что компилятор может в любой момент принять решение о возврате Any или любой другой правильный, но неточный тип возвращаемого значения.

2) см. 1)?

3) Для заданных типов входных аргументов компилятор пытается определить тип возвращаемого значения во время компиляции. Если многократные возможны, это выведет Union тип. Если произойдет полный сбой или будет слишком много разных типов возврата, он выведет Any в качестве типа возврата. В последних случаях фактический тип возвращаемого значения известен только во время выполнения.

Демонстрация 1):

julia> foo(x::Float32) = x
foo (generic function with 1 methods)

julia> foo(x::Int32) = x
foo (generic function with 2 methods)

julia> foo(x::Int64) = x == 1 ? 1 : 1.0
foo (generic function with 3 methods)

julia> Base.return_types(foo)
3-element Array{Any,1}:
 Union{Float64, Int64}
 Int32
 Float32

julia> Base.return_types(foo, (Int64,))
1-element Array{Any,1}:
 Union{Float64, Int64}

julia> Base.return_types(foo, (Int32,))
1-element Array{Any,1}:
 Int32
...