声明一个 Julia 函数,该函数返回一个特定签名的函数。

4
我该如何声明一个 Julia 函数,使其返回具有特定签名的函数?例如,我想要返回一个接受 Int 类型参数并返回 Int 类型值的函数:
function buildfunc()::?????
   mult(x::Int) = x * 2
   return mult
end

这个问号应该用什么替换?


3
Julia没有语法来精确地声明由函数方法返回的方法签名。 请参阅“函数参数猜测”讨论,了解更多思考。 - attdona
2个回答

3
你可以使用Function 类型来实现这一目的。引自Julia文档:

Function是所有函数的抽象类型。

function b(c::Int64)::Int64
        return c+2;
    end

function a()::Function
        return b;        
    end

这将打印:

julia> println(a()(2));

4

Julia会对Float64输入抛出异常。

   julia> println(a()(2.0)); 

错误: MethodError: 没有与 b(::Float64) 匹配的方法 最接近的候选方法是: b(::Int64)


好的,你如何指定返回的函数需要接受一个整数并返回一个整数? - Tarik
据我所知,这是不可能的。在Julia中,有一个抽象类型“Function”,每个函数都是它的具体子类型。没有指定参数类型的中间类型(顺便说一句,这只对方法而不是函数有意义)。 - lungben
谢谢你的回答。其他编程语言(如C)允许声明函数返回的函数的签名,我认为这样做是有合理理由的。即使目的仅仅是为了断言(我认为可能还有其他好的原因),那为什么不呢? - Tarik

3

需要明确一点。在返回的参数上添加类型声明只是一种断言,而不是函数定义的一部分。要了解正在发生的情况,请查看函数的降级代码(这是一种预编译阶段):

julia> f(a::Int)::Int = 2a
f (generic function with 1 method)

julia> @code_lowered f(5)
CodeInfo(
1 ─ %1 = Main.Int
│   %2 = 2 * a
│   %3 = Base.convert(%1, %2)
│   %4 = Core.typeassert(%3, %1)
└──      return %4
)

在这种情况下,由于返回类型是明显的,在编译过程中将实际删除此断言(尝试使用@code_native f(5) 查看自己)。
如果出于某种原因想要生成函数,建议使用@generated 宏。请注意:元编程通常是解决任何Julia相关问题的杀鸡焉用之策。
@generated function f2(x)
    if x <: Int
        quote
            2x
        end
    else
        quote
            10x
        end
    end
end

现在我们有一个名为 f2 的函数,其中 f2 的源代码将依赖于参数类型:

julia> f2(3)
6

julia> f2(3.)
30.0

请注意,这个函数生成实际上是在编译时发生的:
julia> @code_lowered f2(2)
CodeInfo(
    @ REPL[34]:1 within `f2'
   ┌ @ REPL[34]:4 within `macro expansion'
1 ─│ %1 = 2 * x
└──│      return %1
   └
)

希望这样能澄清事情。

感谢您的回答。其他编程语言(如C)允许声明函数返回的函数的签名,我认为这是有合理理由的。即使目的仅仅是为了断言(我认为可能还有其他好的理由),那为什么不呢? - Tarik
因为在99%的情况下,您返回函数而不是方法对象。在多分派语言中,给函数指定类型非常困难。但请参见例如此问题:https://github.com/JuliaLang/julia/issues/33784。 - phipsgabler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接