Julia: 显示来自repl的功能源代码

创建于 2013-03-20  ·  22评论  ·  资料来源: JuliaLang/julia

Julia有很多有用的REPL东西,例如methodshelp
但是,最终我仍然只需要看一下代码,看看它在做什么。
能够做到这一点很酷:

julia> methods(base)
# methods for generic function base
base(base::Integer,n::Integer,pad::Integer) at intfuncs.jl:290
base(symbols::Array{Uint8,N},n::Integer,p::Integer) at intfuncs.jl:291
base(base_or_symbols::Union(Integer,Array{Uint8,N}),n::Integer) at intfuncs.jl:292

julia> implementation(base,1)
base(base::Integer, n::Integer, pad::Integer) = _base(dig_syms,int(base),unsigned(abs(n)),pad,n<0)

julia> implementation(base,3)
base(base_or_symbols::Union(Integer,Array{Uint8}), n::Integer) = base(base_or_symbols, n, 1)

这有点像某些IDE中的跳转代码,但是在REPL中,仅显示一个功能。
这显然有局限性,因为您不能只是向上滚动并查看_base或在该文件中搜索dig_syms的定义,但是它确实可以让您看到默认值是。

您已经可以看到_base的签名,这使base更有意义。 (无需从REPL切换到文本编辑器)

julia> methods(Base._base)
# methods for generic function _base
_base(symbols::Array{Uint8,N},b::Int32,x::Unsigned,pad::Int32,neg::Bool) at intfuncs.jl:278

考虑到行号/文件已经包含在methods的输出中,看来从文件中获取适当的代码行应该很简单。

REPL help wanted

最有用的评论

在我看来,我们仍然支持这一观点

julia> <strong i="6">@code_native</strong> 1 + 2
    .section    __TEXT,__text,regular,pure_instructions
; ┌ @ int.jl:53 within `+'
    leaq    (%rdi,%rsi), %rax
    retq
; └
; ┌ @ int.jl:53 within `<invalid>'
    nopw    %cs:(%rax,%rax)
; └

和这个

julia> <strong i="10">@code_llvm</strong> 1 + 2

;  @ int.jl:53 within `+'
define i64 @"julia_+_13402"(i64, i64) {
top:
  %2 = add i64 %1, %0
  ret i64 %2
}

和这个

julia> <strong i="14">@code_typed</strong> 1 + 2
CodeInfo(
1 ─ %1 = Base.add_int(x, y)::Int64
└──      return %1
) => Int64

和这个

julia> <strong i="18">@code_lowered</strong> 1 + 2
CodeInfo(
1 ─ %1 = Base.add_int(x, y)
└──      return %1
)

不是这个

julia> <strong i="23">@code_source</strong> 1 + 2
ERROR: LoadError: UndefVarError: <strong i="24">@code_source</strong> not defined
in expression starting at REPL[23]:1

我们可以自省一种方法的所有不同版本,使用Julia的每个人都知道如何读写。 我将其标记为“需要帮助”,以表示这是该语言的一种受欢迎的补充,它具有一种可选的模式,使我们能够记住函数的源表示形式。 它可以默认在交互模式下打开,但在非交互模式下默认关闭。

所有22条评论

如果我们在交互运行时存储每个方法定义的源(压缩),则即使源文件发生更改,甚至源行注释不是很完美,这也可以轻松完成并正常工作。 这也将对#265有所帮助(另请参阅本讨论),因为您可以使用源代码重新编译内容。 我们也可以将AST以压缩形式存储-六个而不是六个。

不,它对#265没有帮助。 我们已经掌握了所有信息,只是看起来不再像源代码了。 如果要查看原始代码,最好的方法是从文件中读取它。

同意@JeffBezanson的观点,这将与R背道而驰,在R中键入函数而不用括号阻止源代码。 如果源长度超过几行,它将变得不可用(无法滚动查看输出afaik)。

从文件读取时+1。
更好地修复https://github.com/JuliaLang/julia/issues/2594 ,当start是本机cmd命令并且notepad无法突出显示语法时,它确实杀死了Windows用户也不显示/跳至行号。
edit实际上是一个有用的功能,如果我们可以解决/使其更好的话。

只是想了解一下,在这里是否感觉不应该有一个函数可以呼应方法的源代码,而应该依赖于“ edit”? 在与远程Julia内核进行交互的IPython Web笔记本上,这可能无法很好地发挥作用,因为我认为该文件将在内核的计算机而不是客户端的计算机上打开。

对于它的价值,在交互模式下,我想保留源代码,而不是依赖文件中的内容。 我也希望能够看到通过repl输入的东西的源代码。 另请参阅#3988。

寻呼机支持#6921可以消除对此功能的某些担忧。

我发现这在ipython中非常方便(通过func?? ),尽管-与julia的情况不同-一些函数是隐藏的(例如内置/ cython函数)。

同样, <strong i="5">@less</strong> func(x)几乎可以完成@astrieanna要求的(具有分页),但是它取决于外部的$PAGER

<strong i="5">@less</strong> func(x)不适用于交互式功能,但这似乎是一个问题,应在另一个问题中予以重新说明。

如果以下两个功能可用

  • 获取预先降低的AST代码,即来自repl或运行时的源
  • 重新定义/清除变量/类型/功能/类型

那么就有可能进行运行时代码列表/遍历/操纵/生成。

julia> q=:( function a(i::Int) ; return i+4 ; end ; b=4 ; println(a(b))  )
quote 
    function a(i::Int) # none, line 1:
        return i + 4
    end
    begin 
        b = 4
        println(a(b))
    end
end

julia> function exprdescend(ex) ; if (isa(ex,Expr)) ; println("Descending Expr:",ex) ; println("head:",ex.head); println("args:",ex.args) ; println("type:",ex.typ)  ; for i in ex.args ; exprdescend(i) ; end ; else ; println("*:",typeof(ex),":",ex)  ; end  ;  end
// # ''try it ... long output''

回应评论:JeffBezanson于2013年3月20日发表了评论
“不,它对#265没有帮助。我们已经掌握了所有信息,只是看起来不再像源代码了。如果您要查看原始代码,最好的方法是从文件中读取它。 。”

所以您认为这可能吗? 有包含/要求语句和其他内容时会发生什么?

// # str = read_whole_file_into_a_string(filename)
julia> str="for i in [1,2,3,4] ; println(i) ; end "
julia> s=parse(str)
:(for i = [1,2,3,4] # line 1:
        println(i)
    end)
julia> exprdescend(s)
Descending Expr:for i = [1,2,3,4] # line 1:
    println(i)
end
head:for
args:{:(i = [1,2,3,4]),quote  # line 1:
    println(i)
end}
type:Any
Descending Expr:i = [1,2,3,4]
head:=
args:{:i,:([1,2,3,4])}
type:Any
*:Symbol:i
Descending Expr:[1,2,3,4]
head:vcat
args:{1,2,3,4}
type:Any
*:Int64:1
*:Int64:2
*:Int64:3
*:Int64:4
Descending Expr:begin  # line 1:
    println(i)
end
head:block
args:{:( # line 1:),:(println(i))}
type:Any
*:LineNumberNode: # line 1:
Descending Expr:println(i)
head:call
args:{:println,:i}
type:Any
*:Symbol:println
*:Symbol:i

@hgkamath恐怕我不明白这个问题,但它似乎更适合用户邮件列表。 请务必阅读本手册的反射部分。

另一个用例是@generated函数(来自https://groups.google.com/d/topic/julia-users/4pkWhcap1Zg/discussion)。

哦,我在#22007中解决了吗?

有点–我仍然认为在REPL模式下,我们应该隐藏显示功能的原始来源。

还有一个显示匿名函数的问题,那就是能够显示原始AST很好。

julia> x -> x+1
(::#5) (generic function with 1 method)

不是超级有用。 (另请参见论述。)

在REPL模式下

我们已经基本做到了,访问起来很烦人:

let h = Base.active_repl.interface.modes[1].hist,
    replno = match(r"REPL\[(\d+)\]", $filename)

    replno === nothing || h.history[h.start_idx + parse(Int, replno[1])]
end

“烦人的访问” ==“没有足够的有用性以至于无法解决”

我承认这将是有用的。 我经常通过修改功能并在不同的REPL中运行不同的变体来进行比较来进行调试。 有时我会忘记哪个REPL对应哪个版本。 打印当前定义的函数将很高兴。

https://github.com/MasonProtter/LegibleLambdas.jl提供的Yao用例

每个块都有一个数量为qubit的参数,我们不想重复编写它,因此当您不输入该数量时,它可以自动运行。

julia> using Yao

julia> control(2, 1=>X)
(n -> control(n, 2, 1 => X gate))

因此用户将意识到这不是一个块,因此需要此数量的qubit进行进一步评估。 在拥有LegibleLambdas之前,它只与#42类的数字混淆。 当优化程序之前返回lambda时,Flux也会发生这种情况。

但是在LegibleLambdas中有很多我们无法支持的情况,这很好,我们可以在REPL中直接使用编译器而不是extern包的支持来获取这些信息。

在我看来,我们仍然支持这一观点

julia> <strong i="6">@code_native</strong> 1 + 2
    .section    __TEXT,__text,regular,pure_instructions
; ┌ @ int.jl:53 within `+'
    leaq    (%rdi,%rsi), %rax
    retq
; └
; ┌ @ int.jl:53 within `<invalid>'
    nopw    %cs:(%rax,%rax)
; └

和这个

julia> <strong i="10">@code_llvm</strong> 1 + 2

;  @ int.jl:53 within `+'
define i64 @"julia_+_13402"(i64, i64) {
top:
  %2 = add i64 %1, %0
  ret i64 %2
}

和这个

julia> <strong i="14">@code_typed</strong> 1 + 2
CodeInfo(
1 ─ %1 = Base.add_int(x, y)::Int64
└──      return %1
) => Int64

和这个

julia> <strong i="18">@code_lowered</strong> 1 + 2
CodeInfo(
1 ─ %1 = Base.add_int(x, y)
└──      return %1
)

不是这个

julia> <strong i="23">@code_source</strong> 1 + 2
ERROR: LoadError: UndefVarError: <strong i="24">@code_source</strong> not defined
in expression starting at REPL[23]:1

我们可以自省一种方法的所有不同版本,使用Julia的每个人都知道如何读写。 我将其标记为“需要帮助”,以表示这是该语言的一种受欢迎的补充,它具有一种可选的模式,使我们能够记住函数的源表示形式。 它可以默认在交互模式下打开,但在非交互模式下默认关闭。

现在,由Revise.jl组成的https://github.com/timholy/CodeTracking.jl实现了类似的功能。 我玩了一点,虽然它并不完美,但它经常会起作用。 文档说,同时使用Revise会更好。

这是在讨论中提出的。

与自动区分(例如https://github.com/FluxML/Zygote.jl)结合使用时,这可能是极好的选择,因为您可以将派生代码显示为julia代码

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

wilburtownsend picture wilburtownsend  ·  3评论

omus picture omus  ·  3评论

tkoolen picture tkoolen  ·  3评论

omus picture omus  ·  3评论

TotalVerb picture TotalVerb  ·  3评论