Julia tem várias coisas REPL úteis como methods
e help
.
No entanto, ainda acabo precisando apenas olhar o código para ver o que ele está fazendo.
Seria legal poder fazer:
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)
É como o código de salto em alguns IDEs, mas no REPL, e mostrando apenas uma função.
Isso obviamente tem limitações, já que você não pode simplesmente rolar para cima e ver a implementação de _base
ou pesquisar a definição de dig_syms
naquele arquivo, mas permite que você veja quais são os valores padrão está.
Você já pode ver a assinatura de _base
, o que torna as implementações de base
mais significativas. (sem a necessidade de mudar do REPL para um 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
Considerando que os números de linha / arquivos já estão incluídos na saída de methods
, parece que deve ser simples obter as linhas de código apropriadas do arquivo.
Se armazenássemos a origem (compactada) de cada definição de método ao executar interativamente, isso poderia ser feito com bastante facilidade e funcionar corretamente mesmo quando os arquivos de origem mudam e mesmo quando a anotação da linha de origem não é perfeita. Isso também ajudaria com o # 265 (veja também esta discussão ), já que você pode usar o código-fonte para recompilar as coisas. Também poderíamos armazenar o AST na forma compactada - seis contra meia dúzia.
Não, não vai ajudar com o # 265. Já temos todas as informações, apenas não se parece mais com o código-fonte. Se você quiser examinar o código original, a melhor maneira é lê-lo no arquivo.
Concordar com @JeffBezanson e isso seria um desvio de R, onde digitar a função sem parênteses exclui o código-fonte. Se a origem tiver mais do que algumas linhas, ela se tornará inutilizável (não há como percorrer a página de saída).
+1 com leitura do arquivo.
Melhor correção https://github.com/JuliaLang/julia/issues/2594 , ele realmente mata os usuários do Windows quando start
é um comando nativo cmd
e notepad
não consegue destacar a sintaxe nem mostrar / pular para o número da linha.
edit
é realmente uma função útil, se pudéssemos corrigi-la / torná-la melhor.
Só para entender, é o sentimento aqui que não deveria haver uma função para ecoar o código-fonte dos métodos, mas sim depender de 'editar' para esse propósito? Isso pode não funcionar bem com o notebook da web IPython que está interagindo com um kernel Julia remoto, pois acho que o arquivo será aberto na máquina do kernel em vez da do cliente.
Pelo que vale a pena, em modos interativos, eu gostaria de manter o código-fonte por perto, em vez de confiar no que está nos arquivos. Eu quero ser capaz de ver o código-fonte das coisas que foram inseridas por meio do repl também. Veja também # 3988.
o suporte para pager # 6921 pode negar algumas preocupações sobre a utilidade disso.
Acho isso muito conveniente em ipython (via func??
), embora - ao contrário do que pode ser o caso de julia - algumas funções estejam ocultas (por exemplo, funções internas / cython).
Além disso, <strong i="5">@less</strong> func(x)
faz quase exatamente o que @astrieanna pede (com paginação), mas depende de um $PAGER
externo.
<strong i="5">@less</strong> func(x)
não funciona para funções interativas, mas isso parece ser um problema que deve ser reformulado em uma edição diferente.
Se os dois recursos a seguir estivessem disponíveis
então, pode ser possível fazer a listagem / passagem / manipulação / geração do código de tempo de execução.
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''
em resposta ao comentário: JeffBezanson comentou em 20 de março de 2013
"Não, não vai ajudar com o # 265. Já temos todas as informações, só não se parece mais com o código-fonte. Se você quiser olhar o código original, a melhor maneira é lê-lo do arquivo . "
Então você acha que isso é possível? O que acontece onde há instruções de inclusão / solicitação e outras coisas?
// # 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 Infelizmente não entendi a pergunta, mas parece mais adequada para a lista de discussão dos usuários. Por favor, leia as seções de metaprogramação e reflexão do manual.
Outro caso de uso seria @generated
functions (de https://groups.google.com/d/topic/julia-users/4pkWhcap1Zg/discussion).
Oh, eu resolvi isso no # 22007?
Mais ou menos - ainda acho que no modo REPL devemos esconder a fonte original das funções para exibição.
Há também a questão de exibir funções anônimas, onde seria bom ser capaz de exibir o AST original.
julia> x -> x+1
(::#5) (generic function with 1 method)
não é super útil. (Veja também discurso .)
no modo REPL
já fazemos basicamente, é apenas irritante acessar:
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
"irritante de acessar" == "não é útil o suficiente para ser considerado resolvido"
Admito que seria útil. Eu frequentemente depuro modificando uma função e executando diferentes variações em REPLs diferentes para compará-los. Às vezes, perco a noção de qual REPL corresponde a qual variação. Seria bom ter a impressão da função atualmente definida.
Um caso de uso em Yao fornecido por https://github.com/MasonProtter/LegibleLambdas.jl
Cada bloco tem um argumento de número de qubits, e não queremos escrevê-lo repetidamente, então ele pode ser executado automaticamente quando você não alimentar este número, por exemplo
julia> using Yao
julia> control(2, 1=>X)
(n -> control(n, 2, 1 => X gate))
Assim, o usuário saberá que não se trata de um bloco, ele precisa desse número de qubits para uma avaliação posterior. Antes de termos LegibleLambdas, é bastante confuso com apenas um número como #42
. Isso também acontece com o Flux quando os otimizadores retornam um lambda antes.
Mas existem muitos casos extremos que não podemos suportar no LegibleLambdas, seria bom se pudéssemos obter essas informações diretamente no REPL com o suporte do compilador em vez do pacote externo.
Ainda me parece perverso que apoiemos esta
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)
; └
e isto
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
}
e isto
julia> <strong i="14">@code_typed</strong> 1 + 2
CodeInfo(
1 ─ %1 = Base.add_int(x, y)::Int64
└── return %1
) => Int64
e isto
julia> <strong i="18">@code_lowered</strong> 1 + 2
CodeInfo(
1 ─ %1 = Base.add_int(x, y)
└── return %1
)
mas não isso
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 as diferentes versões possíveis de um método, exceto aquela que todos que usam Julia sabem ler e escrever. Vou marcar isso como "desejo de ajuda" para indicar que seria uma adição bem-vinda à linguagem ter um modo opcional em que lembramos a representação de origem de uma função. Ele pode ser ativado por padrão no modo interativo, mas desativado por padrão no modo não interativo.
Funcionalidades semelhantes agora são implementadas por https://github.com/timholy/CodeTracking.jl , que faz parte do Revise.jl. Eu brinquei um pouco com ele e, embora não seja perfeito, funciona na maioria das vezes. A documentação diz que é muito melhor quando também usa Revise.
Isso foi sugerido nesta discussão .
Isso pode ser excelente em combinação com a diferenciação automática (como https://github.com/FluxML/Zygote.jl), já que você pode mostrar a derivada como código julia
Comentários muito úteis
Ainda me parece perverso que apoiemos esta
e isto
e isto
e isto
mas não isso
Podemos introspectar todas as diferentes versões possíveis de um método, exceto aquela que todos que usam Julia sabem ler e escrever. Vou marcar isso como "desejo de ajuda" para indicar que seria uma adição bem-vinda à linguagem ter um modo opcional em que lembramos a representação de origem de uma função. Ele pode ser ativado por padrão no modo interativo, mas desativado por padrão no modo não interativo.