Julia: mostrar el código fuente de la función de la respuesta

Creado en 20 mar. 2013  ·  22Comentarios  ·  Fuente: JuliaLang/julia

Julia tiene muchas cosas REPL útiles como methods y help .
Sin embargo, todavía termino necesitando solo mirar el código para ver qué está haciendo.
Sería genial poder hacer:

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 como el código de salto en algunos IDE, pero en el REPL, y solo muestra una función.
Esto obviamente tiene limitaciones, ya que no puede simplemente desplazarse hacia arriba y ver la implementación de _base o buscar la definición de dig_syms en ese archivo, pero le permite ver cuáles son los valores predeterminados son.

Ya puede ver la firma de _base , lo que hace que las implementaciones de base más significativas. (sin necesidad de cambiar de REPL a un editor de texto)

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

Teniendo en cuenta que los números de línea / archivos ya están incluidos en la salida de methods , parece que debería ser sencillo tomar las líneas de código adecuadas del archivo.

REPL help wanted

Comentario más útil

Todavía me parece perverso que apoyemos esto

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

y esto

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
}

y esto

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

y esto

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

pero no esto

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

Podemos introspectar todas las diferentes versiones posibles de un método, excepto la que todos los que usan Julia saben leer y escribir. Voy a marcar esto como "se busca ayuda" para indicar que sería una adición bienvenida al lenguaje tener un modo opcional donde recordamos la representación fuente de una función. Se puede activar de forma predeterminada en el modo interactivo, pero se puede desactivar de forma predeterminada en el modo no interactivo.

Todos 22 comentarios

Si almacenamos la fuente (comprimida) de cada definición de método cuando se ejecuta de forma interactiva, esto podría hacerse con bastante facilidad y funcionar correctamente incluso cuando los archivos fuente cambian e incluso cuando la anotación de la línea fuente no es del todo perfecta. Eso también ayudaría con el # 265 (vea también esta discusión ) ya que podría usar la fuente para recompilar cosas. En su lugar, también podríamos almacenar el AST en forma comprimida: seis frente a media docena.

No, no ayudará con el # 265. Ya tenemos toda la información, simplemente ya no parece un código fuente. Si desea ver el código original, la mejor manera es leerlo desde el archivo.

De acuerdo con @JeffBezanson y esto sería una desviación de R, donde escribir la función sin parens elimina el código fuente. Si la fuente tiene más de unas pocas líneas, se vuelve inutilizable (no hay forma de desplazarse por la salida afaik).

+1 con lectura de archivo.
Mejor solución https://github.com/JuliaLang/julia/issues/2594 , realmente mata a los usuarios de Windows cuando start es un comando nativo cmd y notepad no puede resaltar la sintaxis ni mostrar / saltar al número de línea.
edit es realmente una función útil, si pudiéramos arreglarlo / mejorarlo.

Solo para entender, ¿se siente aquí que no debería haber una función para hacer eco del código fuente de los métodos, sino más bien confiar en 'editar' para ese propósito? Es posible que eso no funcione bien con el cuaderno web IPython que interactúa con un kernel de Julia remoto, ya que creo que el archivo se abrirá en la máquina del kernel en lugar de en la del cliente.

Por lo que vale, en modos interactivos, me gustaría mantener el código fuente, en lugar de confiar en lo que hay en los archivos. También quiero poder ver el código fuente de las cosas que se ingresaron a través de la respuesta. Vea también # 3988.

El soporte de buscapersonas # 6921 puede anular algunas preocupaciones sobre la utilidad de esto.

Encuentro esto muy conveniente en ipython (a través de func?? ), aunque, a diferencia de lo que podría ser el caso de julia, algunas funciones están ocultas (por ejemplo, funciones integradas / cython).

Además, <strong i="5">@less</strong> func(x) hace casi exactamente lo que pide @astrieanna (con paginación), pero depende de un $PAGER externo.

<strong i="5">@less</strong> func(x) no funciona para funciones interactivas, pero ese parece ser un problema que debería reformularse en una edición diferente.

Si las siguientes dos funciones estuvieran disponibles

  • obtener código AST pre-reducido, es decir, fuente de la respuesta o en tiempo de ejecución
  • redefinir / borrar variables / tipos / funciones / tipos

entonces puede ser posible hacer un listado / recorrido / manipulación / generación de código en tiempo de ejecución.

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

en respuesta al comentario: JeffBezanson comentó el 20 de marzo de 2013
"No, no ayudará con el # 265. Ya tenemos toda la información, simplemente ya no parece el código fuente. Si desea ver el código original, la mejor manera es leerlo desde el archivo . "

¿Entonces crees que esto es posible? ¿Qué sucede cuando hay declaraciones de inclusión / solicitud y otras cosas?

// # 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 Me temo que no entiendo la pregunta, pero parece más adecuada para la lista de correo de los usuarios. Lea las secciones de metaprogramación y reflexión del manual.

Otro caso de uso serían las funciones @generated (de https://groups.google.com/d/topic/julia-users/4pkWhcap1Zg/discussion).

Oh, ¿resolví esto en el # 22007?

Más o menos, sigo pensando que en el modo REPL deberíamos guardar la fuente original de las funciones para mostrar.

También está la cuestión de mostrar funciones anónimas, donde sería bueno poder mostrar el AST original.

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

no es muy útil. (Ver también discurso .)

en modo REPL

básicamente ya lo hacemos, es molesto acceder:

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

"molesto para acceder" == "no es lo suficientemente útil como para ser considerado resuelto"

Admito que sería útil. Con frecuencia depuro modificando una función y ejecutando diferentes variaciones en diferentes REPL para compararlos. A veces pierdo la pista de qué REPL corresponde a qué variación. Sería bueno tener la impresión de la función que está definida actualmente.

Un caso de uso en Yao proporcionado por https://github.com/MasonProtter/LegibleLambdas.jl

Cada bloque tiene un argumento de número de qubits, y no queremos escribirlo repetidamente, por lo que se puede cursar automáticamente cuando no ingresa este número, por ejemplo

julia> using Yao

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

Por lo tanto, el usuario sabrá que esto no es un bloque, necesita este número de qubits para una evaluación adicional. Antes de que tengamos LegibleLambdas, es bastante confuso con solo un número como #42 . Esto también le sucede a Flux cuando los optimizadores devuelven un lambda antes.

Pero hay muchos casos de esquina que no podemos admitir en LegibleLambdas, sería bueno que pudiéramos obtener directamente esta información en REPL con el soporte del compilador en lugar del paquete externo.

Todavía me parece perverso que apoyemos esto

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

y esto

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
}

y esto

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

y esto

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

pero no esto

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

Podemos introspectar todas las diferentes versiones posibles de un método, excepto la que todos los que usan Julia saben leer y escribir. Voy a marcar esto como "se busca ayuda" para indicar que sería una adición bienvenida al lenguaje tener un modo opcional donde recordamos la representación fuente de una función. Se puede activar de forma predeterminada en el modo interactivo, pero se puede desactivar de forma predeterminada en el modo no interactivo.

Https://github.com/timholy/CodeTracking.jl , que forma parte de Revise.jl, implementa una funcionalidad similar. Jugué un poco con él, y aunque no es perfecto, funciona la mayoría de las veces. La documentación dice que es mucho mejor cuando también se usa Revise.

Esto se sugirió en esta discusión .

Esto podría ser excelente en combinación con la diferenciación automática (como https://github.com/FluxML/Zygote.jl), ya que luego puede mostrar la derivada como código julia

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

musm picture musm  ·  3Comentarios

wilburtownsend picture wilburtownsend  ·  3Comentarios

sbromberger picture sbromberger  ·  3Comentarios

dpsanders picture dpsanders  ·  3Comentarios

felixrehren picture felixrehren  ·  3Comentarios