Julia: Funktionsquellcode von repl anzeigen

Erstellt am 20. März 2013  ·  22Kommentare  ·  Quelle: JuliaLang/julia

Julia hat viele nützliche REPL-Dinge wie methods und help .
Am Ende muss ich mir jedoch nur den Code ansehen, um zu sehen, was er tut.
Es wäre cool, Folgendes tun zu können:

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)

Es ist ein bisschen wie das Jump-to-Code-Zeug in einigen IDEs, aber in der REPL, und zeigt nur die eine Funktion.
Dies hat natürlich Einschränkungen, da Sie nicht einfach nach oben scrollen und die Implementierung von _base oder nach der Definition von dig_syms in dieser Datei suchen können, aber Sie können die Standardwerte sehen sind.

Sie können bereits die Signatur für _base , wodurch die Implementierungen von base aussagekräftiger werden. (ohne von der REPL zu einem Texteditor wechseln zu müssen)

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

In Anbetracht der Tatsache, dass die Zeilennummern / Dateien bereits in der Ausgabe von methods , scheint es unkompliziert zu sein, die entsprechenden Codezeilen aus der Datei abzurufen.

REPL help wanted

Hilfreichster Kommentar

Es scheint mir immer noch pervers, dass wir dies unterstützen

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)
; └

und das

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
}

und das

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

und das

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

aber nicht das

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

Wir können alle möglichen Versionen einer Methode überprüfen , mit

Alle 22 Kommentare

Wenn wir die Quelle (komprimiert) jeder Methodendefinition bei interaktiver Ausführung speichern, könnte dies ziemlich einfach und korrekt funktionieren, selbst wenn sich Quelldateien ändern und selbst wenn die Annotation der Quellzeile nicht ganz perfekt ist. Das würde auch bei # 265 helfen (siehe auch diese Diskussion ), da Sie die Quelle verwenden könnten, um Dinge neu zu kompilieren. Wir könnten den AST stattdessen auch in komprimierter Form speichern - sechs gegen ein halbes Dutzend.

Nein, mit # 265 hilft es nicht. Wir haben bereits alle Informationen, es sieht einfach nicht mehr wie Quellcode aus. Wenn Sie sich den Originalcode ansehen möchten, lesen Sie ihn am besten aus der Datei.

Stimmen Sie mit

+1 mit aus Datei lesen.
Besser https://github.com/JuliaLang/julia/issues/2594 , es tötet Windows-Benutzer wirklich, wenn start ein nativer cmd Befehl ist und notepad die Syntax nicht hervorheben kann noch zeigen / springen zur Zeilennummer.
edit ist wirklich eine nützliche Funktion, wenn wir sie reparieren / verbessern könnten.

Nur um zu verstehen, gibt es hier das Gefühl, dass es keine Funktion geben sollte, um den Quellcode von Methoden wiederzugeben, sondern sich zu diesem Zweck auf "Bearbeiten" zu verlassen? Das funktioniert möglicherweise nicht gut mit dem IPython-Webnotizbuch, das mit einem Remote-Julia-Kernel interagiert, da ich denke, dass die Datei auf dem Computer des Kernels anstelle des Clients geöffnet wird.

Für das, was es wert ist, möchte ich in interaktiven Modi den Quellcode beibehalten, anstatt mich auf die Inhalte der Dateien zu verlassen. Ich möchte in der Lage sein, den Quellcode von Dingen zu sehen, die auch über die Antwort eingegeben wurden. Siehe auch # 3988.

Die Pager-Unterstützung Nr. 6921 kann einige Bedenken hinsichtlich der Nützlichkeit zunichte machen.

Ich finde das in ipython sehr praktisch (über func?? ), obwohl - anders als bei julia - einige Funktionen versteckt sind (z. B. eingebaute / cython-Funktionen).

Außerdem macht <strong i="5">@less</strong> func(x) fast genau das, was @astrieanna verlangt (mit Paging), aber es hängt von einem externen $PAGER .

<strong i="5">@less</strong> func(x) funktioniert nicht für interaktive Funktionen, aber das scheint ein Problem zu sein, das in einem anderen Problem umformuliert werden sollte.

Wenn die folgenden zwei Funktionen verfügbar wären

  • Abrufen des vorab gesenkten AST-Codes, dh der Quelle von der Replik oder zur Laufzeit
  • Variablen / Typen / Funktionen / Typen neu definieren / löschen

dann kann es möglich sein, eine Laufzeitcode-Auflistung / Durchquerung / Manipulation / Generierung durchzuführen.

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''

als Antwort auf den Kommentar: JeffBezanson kommentierte am 20. März 2013
"Nein, es wird bei # 265 nicht helfen. Wir haben bereits alle Informationen, es sieht einfach nicht mehr wie Quellcode aus. Wenn Sie sich den Originalcode ansehen möchten, lesen Sie ihn am besten aus der Datei . "

Sie denken also, dass dies möglich ist? Was passiert, wenn Include / Require-Anweisungen und andere Dinge vorhanden sind?

// # 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 Ich fürchte, ich verstehe die Frage nicht, aber sie scheint besser für die Mailingliste der Benutzer geeignet zu sein. Bitte lesen Sie die Abschnitte zur Metaprogrammierung und Reflexion des Handbuchs.

Ein weiterer Anwendungsfall wären @generated -Funktionen (von https://groups.google.com/d/topic/julia-users/4pkWhcap1Zg/discussion).

Oh, habe ich das in # 22007 gelöst?

Art von - Ich denke immer noch, dass wir im REPL-Modus die ursprüngliche Quelle für Funktionen für die Anzeige verstauen sollten.

Es stellt sich auch die Frage, ob anonyme Funktionen angezeigt werden sollen, bei denen es schön wäre, den ursprünglichen AST anzeigen zu können.

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

ist nicht super nützlich. (Siehe auch Diskurs .)

im REPL-Modus

Wir tun es bereits im Grunde, es ist nur ärgerlich, darauf zuzugreifen:

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

"ärgerlich zuzugreifen" == "nicht nützlich genug, um als gelöst angesehen zu werden"

Ich gebe zu, dass es nützlich wäre. Ich debugge häufig, indem ich eine Funktion in verschiedenen REPLs ändere und verschiedene Variationen ausführe, um sie zu vergleichen. Manchmal verliere ich den Überblick darüber, welche REPL welcher Variation entspricht. Das Drucken der aktuell definierten Funktion wäre dann schön.

Ein Anwendungsfall in Yao, bereitgestellt von https://github.com/MasonProtter/LegibleLambdas.jl

Jeder Block hat ein Argument für die Anzahl der Qubits, und wir möchten es nicht wiederholt schreiben, sodass es automatisch ausgeführt werden kann, wenn Sie diese Anzahl nicht eingeben, z

julia> using Yao

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

Dem Benutzer ist also bewusst, dass dies kein Block ist. Er benötigt diese Anzahl von Qubits für die weitere Auswertung. Bevor wir LegibleLambdas haben, ist es ziemlich verwirrend mit nur einer Zahl wie #42 . Dies passiert auch bei Flux, wenn die Optimierer zuvor ein Lambda zurückgegeben haben.

Es gibt jedoch viele Eckfälle, die wir in LegibleLambdas nicht unterstützen können. Es wäre schön, wenn wir diese Informationen direkt in REPL mit der Unterstützung des Compilers anstelle des externen Pakets abrufen könnten.

Es scheint mir immer noch pervers, dass wir dies unterstützen

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)
; └

und das

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
}

und das

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

und das

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

aber nicht das

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

Wir können alle möglichen Versionen einer Methode überprüfen , mit

Eine ähnliche Funktionalität wird jetzt von https://github.com/timholy/CodeTracking.jl implementiert, das Teil von Revise.jl ist. Ich habe ein wenig damit gespielt, und obwohl es nicht perfekt ist, funktioniert es meistens. Die Dokumentation sagt, dass es viel besser ist, wenn Sie auch Revise verwenden.

Dies wurde in dieser Diskussion vorgeschlagen .

Dies kann in Kombination mit einer automatischen Differenzierung (wie https://github.com/FluxML/Zygote.jl) hervorragend sein, da Sie die Ableitung dann als Julia-Code anzeigen können

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen