是否可以在未评估的上下文中获取Julia函数的返回类型?

时间:2019-10-10 17:46:55

标签: julia

我想在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 ++背景下,我要问的是Julia中有一个std::result_of等效项。问题与this one几乎相同,但是语言是朱莉娅。


经过一些研究,我发现Julia在一个函数中允许不同类型的返回值,其中类型推断看起来非常困难。例如,

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

现在,根据输入值,返回类型可以为Int64Float64。不过,在这种情况下,我仍然想知道是否有一些宏技巧可以推断出返回类型为Union{ Int64, Float64 }


总而言之,我的问题是:

  1. 从根本上讲,是否可以仅通过在Julia中提供参数类型来获得函数的返回类型?
  2. 如果不可能使用1,则对于具有一种确定性返回类型的函数(如第一个示例中所示),是否有可能使返回类型未经评估?
  3. (可能与我想要的无关,但我认为它可以增进我的理解)编译Julia代码时,是否知道函数的返回类型?还是仅在运行时确定类型信息?

1 个答案:

答案 0 :(得分:8)

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