julia - 在 Julia 中,如何正确地对调用者提供的(超)类型的参数进行方法分派(dispatch)?

标签 julia

我想定义一个函数f(x, t::Type)根据 isa(x, t) 是否执行不同的行为.假设我想调用b1(x)如果是,b2(x)除此以外。

我知道我可以像这样在运行时进行动态检查:

function f(x, t::Type)
  if isa(x, t)
    b1(x)
  else
    b2(x)
  end
end

但是,有没有办法纯粹通过参数方法调度来做到这一点?例如,如果我定义
f{T}(x::T, t::Type{T}) = b1(x)
f(x, t::Type) = b2(x)

对于 f(1, Int)f(1.0, Int)调用正确的行为。但我希望这也适用于 t 的所有子类型:
f(1, Number)

这实际上调用了 b2因为f的第一个签名不匹配。有趣的是,f(x::Number, t::Type{Number}) = b1(x)在这种情况下会匹配。

我在这里遗漏了一些明显的东西吗?

这显然是一个错误,并在 0.4 中修复。

问题:
  • 为什么f{T}(x::T, t::Type{T})不匹配 f(1, Number) , 即使有 T 的类型替换( Number ) 那会匹配吗?
  • 使用 f{T2, T1 <: T2}(x::T1, t::Type{T2})或类似的东西不起作用,因为似乎所有静态参数只有在完整的静态参数列表关闭后才进入范围。为什么?
  • 使用动态方法是否有任何性能损失?
  • 将方法定义为内部函数怎么样,所以我可以绑定(bind) t到一个局部变量,像这样:function f(x, t::Type); g(x::t) = b1(x); g(x) = b2(x); g(x) end
    这行得通,但性能成本是多少?
  • 解决这个问题的惯用/首选方法是什么?

  • (我在 0.3.2 上试过这个。)

    最佳答案

    要回答您的问题:

  • AFAICT 它应该。正如 user3580870 评论的那样,这似乎在 Julia 0.4 中有效。
  • 这是“三角调度”,(尚未)实现。见 #3766 .
  • 依靠。编译器可以评估 isa(x, t)在编译时并消除分支。但是,仍有一些可能的方法使用 isa可能不是最理想的:
  • 如果两个分支返回不同的类型,类型推断将无法正确推断返回类型,因为它发生在 isa(x, t) 之前。被制成一个常数。 (这可能代价高昂;下面其他可能的去优化可能没什么大不了的。)
  • 如果一个分支执行堆分配而另一个不执行,则可能会发出不必要的 GC 帧。
  • 该函数可能未内联。
  • 内部函数将具有与使用 isa 相同的性能问题。和更多。从 Julia 0.5 开始,在这种情况下,内部函数应该与顶级函数一样高效。
  • 提交错误;-)。我认为这应该有效。有可能在 0.4 中修复此问题的任何内容都可以向后移植到 0.3。但如果做不到这一点,isa只要它不会导致类型推断问题,这不是一个坏方法。
  • 关于julia - 在 Julia 中,如何正确地对调用者提供的(超)类型的参数进行方法分派(dispatch)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26847790/

    相关文章:

    Julia:不带单引号的美元符号命令

    julia - 在 Julia 脚本中,您能否判断该脚本是否已导入或直接执行?

    design-patterns - 在 Julia 模块中自动导出函数的语法

    optimization - 打印IPOPT参数

    julia - 如何找到非泛型函数的来源?

    python - 阶乘函数在 Python 中工作,为 Julia 返回 0

    julia - 将单个数字添加到 julia 数据框中的列?

    arrays - 如何用给定的值(不是对象引用)填充数组?

    python - 使用 Julia NetCDF.jl 包将值附加到 netCDF4 变量

    string - Julia:将数字字符串转换为 float 或 int