gpt4 book ai didi

julia - 如何将一个函数作为参数传递给 Julia 中的另一个函数?

转载 作者:行者123 更新时间:2023-12-04 22:28:08 50 4
gpt4 key购买 nike

我们可以将一个函数作为 julia 中另一个函数的参数传递吗?它是如何工作的?这是否意味着输入函数在调用函数之前运行,或者输入函数只有在调用函数专门调用它时才会被调用?

最佳答案

Julia 最大的特点之一是您可以自己挖掘出这些问题的答案。与其做实验,然后观察表面上的行为,直接问 Julia 它在幕后做了什么,是一种更方便、更简洁的方式来获得答案。让我们从其他两个答案中借用这些示例,并通过 @code_lowered 询问 Julia 发生了什么。 :

julia> f() = println("hello world")
julia> g(any_func::Function) = any_func()

#Me: hi, Julia, what happened here?
julia> @code_lowered g(f)

#Julia: hi there, this is the lowered code, anything else you want to know?
CodeInfo(:(begin
nothing
return (any_func)()
end))
#Me: it looks like function `g` just returned `(any_func)()` and did nothing else,
# is it equvienlent to write `f()`?
julia> @code_typed g(f)

#Julia: yes, the codes looks the same after type inference stage:
CodeInfo(:(begin
$(Expr(:inbounds, false))
# meta: location REPL[1] f 1
# meta: location coreio.jl println 5
SSAValue(0) = (Core.typeassert)(Base.STDOUT, Base.IO)::IO
# meta: pop location
# meta: pop location
$(Expr(:inbounds, :pop))
return (Base.print)(SSAValue(0), "hello world", $(QuoteNode('\n')))::Void
end))=>Void

julia> @code_typed f()
CodeInfo(:(begin
$(Expr(:inbounds, false))
# meta: location coreio.jl println 5
SSAValue(0) = (Core.typeassert)(Base.STDOUT, Base.IO)::IO
# meta: pop location
$(Expr(:inbounds, :pop))
return (Base.print)(SSAValue(0), "hello world", $(QuoteNode('\n')))::Void
end))=>Void

Does this mean the input function is run before the calling function?



在这种特殊情况下,很难回答,调用函数 g在编译时被编译器优化,所以没有 g在运行时。 :P 让我们添加一些额外的内容到 g :
julia> g(any_func::Function) = (println("I don't wanna be optimized out!"); any_func())
g (generic function with 1 method)
julia> @code_lowered g(f)
CodeInfo(:(begin
nothing
(Main.println)("I don't wanna be optimized out!")
return (any_func)()
end))
julia> @code_typed g(f)
CodeInfo(:(begin
$(Expr(:inbounds, false))
# meta: location coreio.jl println 5
SSAValue(0) = (Core.typeassert)(Base.STDOUT, Base.IO)::IO
# meta: pop location
$(Expr(:inbounds, :pop))
(Base.print)(SSAValue(0), "I don't wanna be optimized out!", $(QuoteNode('\n')))::Void
$(Expr(:inbounds, false))
# meta: location REPL[2] f 1
# meta: location coreio.jl println 5
SSAValue(1) = (Core.typeassert)(Base.STDOUT, Base.IO)::IO
# meta: pop location
# meta: pop location
$(Expr(:inbounds, :pop))
return (Base.print)(SSAValue(1), "hello world", $(QuoteNode('\n')))::Void
end))=>Void

此示例显示 g 的内容将在 f 之前运行,所以答案是肯定的。遵循相同的模式,很容易查看 Liso 的示例:
julia> f = x->x+1
julia> fun(f::Function, a) = f(a)

# nothing new here, `f(9)` was called before `fun`
# and the return value was passed to `fun` with a binding name `a`.
julia> @code_lowered fun(f, f(9))
CodeInfo(:(begin
nothing
return (f)(a)
end))

# to verify your second question:
julia> foo(f, x) = x
foo (generic function with 1 method)

julia> @code_lowered foo(f, 1)
CodeInfo(:(begin
nothing
return x
end))

Does the input function only get called if the calling function calls it specifically?



所以是的,上面的例子表明如果 f未被调用函数调用 foo ,会直接优化出来。

与其他语言不同,Julia 不仅仅是一个对用户不透明的魔法黑匣子,有时打开盒子自学成才是高效的。顺便说一句,Julia 中还有两个阶段(@code_llvm,@code_native),您可能需要转储这些低级代码以进行一些高级调查,请参阅 Stefan 在这篇文章中的精彩回答: What is the difference between @code_native, @code_typed and @code_llvm in Julia?了解更多详情。

更新:

what is different between these functions: g1() = f() , g2(f::Function) = f(). Results for both of them are the same, so What is different between them?


julia> @code_lowered g1()
CodeInfo(:(begin
nothing
return (Main.f)()
end))

julia> @code_lowered g2(f)
CodeInfo(:(begin
nothing
return (f)()
end))

降低的代码告诉 g1()总是返回 Main.f() ,这里是 Main.ffMain模块,但 g2返回 f()在哪里 f是您传递给它的函数。为了清楚起见,我们可以定义 g2作为:
julia> g2(argumentf::Function) = argumentf()
g2 (generic function with 1 method)

julia> @code_lowered g2(f)
CodeInfo(:(begin
nothing
return (argumentf)()
end))
g2是“将函数作为另一个函数的参数传递”, g1可以认为是 Main.f 的别名.你能理解这个吗? @红色的

关于julia - 如何将一个函数作为参数传递给 Julia 中的另一个函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46842510/

50 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com