Julia: إظهار رمز مصدر وظيفة من رد

تم إنشاؤها على ٢٠ مارس ٢٠١٣  ·  22تعليقات  ·  مصدر: JuliaLang/julia

لدى جوليا الكثير من أشياء REPL المفيدة مثل methods و help .
ومع ذلك ، ما زلت في نهاية المطاف بحاجة إلى مجرد إلقاء نظرة على الكود لمعرفة ما يفعله.
سيكون من الرائع أن تكون قادرًا على القيام بما يلي:

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)

إنه يشبه نوعًا ما عناصر الانتقال إلى التعليمات البرمجية في بعض IDEs ، ولكن في 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

يمكننا استبطان جميع الإصدارات المختلفة الممكنة لطريقة ما باستثناء تلك التي يعرفها كل شخص يستخدم جوليا كيف يقرأ ويكتب. سأضع علامة على هذا على أنه "مطلوب مساعدة" للإشارة إلى أنه سيكون إضافة مرحب بها إلى اللغة أن يكون لديك وضع اختياري حيث نتذكر تمثيل المصدر لوظيفة ما. يمكن تشغيله افتراضيًا في الوضع التفاعلي ولكن يتم إيقاف تشغيله افتراضيًا في الوضع غير التفاعلي.

ال 22 كومينتر

إذا قمنا بتخزين المصدر (المضغوط) لكل تعريف طريقة عند التشغيل التفاعلي ، فيمكن القيام بذلك بسهولة إلى حد ما والعمل بشكل صحيح حتى عندما تتغير ملفات المصدر وحتى عندما لا يكون التعليق التوضيحي في سطر المصدر مثاليًا تمامًا. سيساعد ذلك أيضًا في # 265 (انظر أيضًا هذه المناقشة ) حيث يمكنك استخدام المصدر لإعادة تجميع الأشياء. يمكننا أيضًا تخزين AST في شكل مضغوط بدلاً من ذلك - ستة مقابل نصف دزينة.

لا ، لن يساعد مع # 265. لدينا بالفعل جميع المعلومات ، لكنها لم تعد تبدو مثل شفرة المصدر بعد الآن. إذا كنت تريد إلقاء نظرة على الكود الأصلي ، فإن أفضل طريقة هي قراءته من الملف.

اتفق مع JeffBezanson وسيكون هذا خروجًا عن R حيث تؤدي كتابة الوظيفة بدون أقواس إلى إخراج الكود المصدري. إذا كان المصدر أكثر من بضعة أسطر طويلة ، فإنه يصبح غير قابل للاستخدام (لا توجد طريقة للتمرير خلال الإخراج afaik).

+1 مع القراءة من الملف.
إصلاح أفضل https://github.com/JuliaLang/julia/issues/2594 ، إنه يقتل مستخدمي Windows حقًا عندما يكون الأمر start أصليًا cmd أمر و notepad لا يمكن تمييز بناء الجملة ولا إظهار / الانتقال إلى رقم السطر.
edit هي وظيفة مفيدة حقًا ، إذا تمكنا من إصلاحها / تحسينها.

فقط لفهم ، هل الشعور هنا أنه لا ينبغي أن تكون هناك وظيفة لترديد الشفرة المصدر للطرق ، بل الاعتماد على "تحرير" لهذا الغرض؟ قد لا يعمل ذلك بشكل جيد مع دفتر ويب IPython الذي يتفاعل مع نواة Julia عن بُعد ، لأنني أعتقد أن الملف سيفتح على جهاز kernel بدلاً من جهاز العميل.

لما يستحق ، في الأوضاع التفاعلية ، أود الاحتفاظ بالشفرة المصدر ، بدلاً من الاعتماد على ما هو موجود في الملفات. أريد أن أكون قادرًا على رؤية الكود المصدري للأشياء التي تم إدخالها عبر الرد أيضًا. أنظر أيضا # 3988.

قد ينفي دعم بيجر # 6921 بعض المخاوف بشأن فائدة ذلك.

أجد هذا مناسبًا جدًا في ipython (عبر func?? ) ، على الرغم من - على عكس حالة جوليا - يتم إخفاء بعض الوظائف (مثل الدوال المضمنة / cython).

أيضًا ، يقوم <strong i="5">@less</strong> func(x) تقريبًا بما يطلبه astrieanna (مع الترحيل) ، ولكنه يعتمد على $PAGER خارجي.

<strong i="5">@less</strong> func(x) للوظائف التفاعلية ، ولكن يبدو أن هذه مشكلة يجب إعادة صياغتها في مشكلة مختلفة.

إذا توفرت السمتان التاليتان

  • الحصول على كود AST الذي تم تخفيضه مسبقًا ، أي مصدر من البديل أو في وقت التشغيل
  • إعادة تعريف / مسح المتغيرات / الأنواع / الوظائف / الأنواع

ثم قد يكون من الممكن القيام بتشغيل قائمة رمز وقت / الاجتياز / التلاعب / الجيل.

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 في 20 مارس 2013
"لا ، لن يساعد ذلك في # 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

"مزعج للوصول" == "ليس مفيدًا بدرجة كافية ليتم اعتباره محلولًا"

أعترف أنه سيكون مفيدًا. كثيرًا ما أقوم بتصحيح الأخطاء عن طريق تعديل دالة في أشكال مختلفة وتشغيلها في REPLs مختلفة لمقارنتها. أحيانًا أفقد المسار الذي يتوافق مع REPL مع أي اختلاف. سيكون من الجيد عندئذٍ طباعة الوظيفة المحددة حاليًا.

حالة استخدام في ياو مقدمة من https://github.com/MasonProtter/LegibleLambdas.jl

تحتوي كل كتلة على وسيطة لعدد الكيوبتات ، ولا نريد كتابتها بشكل متكرر ، لذلك يمكن معالجتها تلقائيًا عندما لا تقوم بإدخال هذا الرقم ، على سبيل المثال

julia> using Yao

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

لذلك سوف يدرك المستخدم أن هذا ليس كتلة ، فهو بحاجة إلى هذا العدد من البتات لمزيد من التقييم. قبل أن يكون لدينا LegibleLambdas ، يكون الأمر محيرًا تمامًا مع مجرد رقم مثل #42 . يحدث هذا أيضًا لـ Flux عندما تقوم Optimizers بإرجاع lambda من قبل.

ولكن هناك الكثير من الحالات التي لا يمكننا دعمها في LegibleLambdas ، سيكون من الجيد أن نحصل على هذه المعلومات مباشرة في REPL بدعم من مترجم بدلاً من الحزمة الخارجية.

لا يزال يبدو لي أنه من المنحرف أننا نؤيد هذا

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

يمكننا استبطان جميع الإصدارات المختلفة الممكنة لطريقة ما باستثناء تلك التي يعرفها كل شخص يستخدم جوليا كيف يقرأ ويكتب. سأضع علامة على هذا على أنه "مطلوب مساعدة" للإشارة إلى أنه سيكون إضافة مرحب بها إلى اللغة أن يكون لديك وضع اختياري حيث نتذكر تمثيل المصدر لوظيفة ما. يمكن تشغيله افتراضيًا في الوضع التفاعلي ولكن يتم إيقاف تشغيله افتراضيًا في الوضع غير التفاعلي.

يتم الآن تنفيذ وظائف مماثلة بواسطة https://github.com/timholy/CodeTracking.jl ، وهو جزء من Revise.jl. لقد لعبت معها قليلاً ، وعلى الرغم من أنها ليست مثالية ، إلا أنها تعمل في كثير من الأحيان. تشير الوثائق إلى أنه أفضل بكثير عند استخدام Revise أيضًا.

تم اقتراح هذا في هذه المناقشة .

قد يكون هذا ممتازًا مع التمايز التلقائي (مثل https://github.com/FluxML/Zygote.jl) ، حيث يمكنك بعد ذلك إظهار المشتق كرمز جوليا

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات