Julia: تؤدي قواعد النطاق المتغير العام إلى سلوك غير بديهي في REPL / دفتر الملاحظات

تم إنشاؤها على ٢١ أغسطس ٢٠١٨  ·  98تعليقات  ·  مصدر: JuliaLang/julia

مثال 1

جاء هذا مع طالب قام بالترقية من 0.6 إلى 1.0 مباشرةً ، لذلك لم تتح له الفرصة مطلقًا لرؤية تحذير بالإيقاف ، ناهيك عن إيجاد تفسير لسلوك جديد:

julia> beforefor = true
true

julia> for i in 1:2
         beforefor = false
       end

julia> beforefor  # this is surprising bit
true

julia> beforeif = true
true

julia> if 1 == 1
         beforeif = false
       end
false

julia> beforeif  # Another surprise!
false

julia> function foo()
         infunc = true
         for i in 1:10
           infunc = false
         end
         <strong i="7">@show</strong> infunc
       end
foo (generic function with 1 method)

julia> foo()  # "I don't get this"
infunc = false 

مثال 2

julia> total_lines = 0
0

julia> list_of_files = ["a", "b", "c"]
3-element Array{String,1}:
 "a"
 "b"
 "c"

julia> for file in list_of_files
         # fake read file
         lines_in_file = 5
         total_lines += lines_in_file
       end
ERROR: UndefVarError: total_lines not defined
Stacktrace:
 [1] top-level scope at ./REPL[3]:4 [inlined]
 [2] top-level scope at ./none:0

julia> total_lines  # This crushs the students willingness to learn
0

"فهمت" سبب حدوث ذلك بالمعنى الذي أعتقد أنه يمكنني شرحه ، مع إشارة كافية إلى الأسرار في الدليل حول ما يقدم النطاقات وما لا يقدم ، لكنني أعتقد أن هذا يمثل مشكلة للاستخدام التفاعلي.

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

لست متأكدًا من القواعد في Python ، لكنني أعلم أنه لا يمكنك عمومًا تعيين أشياء على النطاق العالمي دون استدعاء global. ولكن في REPL يعمل ، ربما لأن القواعد مختلفة في REPL أو يتم تطبيق نفس المنطق كما لو كانوا جميعًا في نطاق الوظيفة.

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

المراجع المتقاطعة:

19324

https://discourse.julialang.org/t/repl-and-for-loops-scope-behavior-change/13514
https://stackoverflow.com/questions/51930537/scope-of-variables-in-julia

REPL minor change

التعليق الأكثر فائدة

JeffBezanson ، تذكر أن الكثير منا يود استخدام Julia كبديل لماتلاب إلى آخره في الدورات التقنية مثل الجبر الخطي والإحصاء. هذه ليست دورات برمجة وغالبًا ما لا يمتلك الطلاب أي خلفية عن البرمجة. ونحن لم تفعل البرمجة المهيكلة - انها تقريبا كل التفاعلي مع قصاصات قصيرة والمتغيرات العالمية.

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

ال 98 كومينتر

(لكل mlubin ، هذا هو التغيير ذي الصلة https://github.com/JuliaLang/julia/pull/19324)

اقترح ستيفان هنا أن أحد الاحتمالات لحل هذه المشكلة هو التغليف التلقائي لإدخالات REPL في كتل let

لكن ألن يكون هذا محيرًا لأنك لا تستطيع فعله

a = 1

واستخدام a بعد ذلك؟ ما لم يتم إدراج global لجميع مهام المستوى الأعلى ، أعتقد؟

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

لذلك ستحول a = 1 إلى شيء مثل a = let a; a = 1; end . وشيء من هذا القبيل

for i in 1:2
    before = false
end

سوف يتحول إلى هذا:

before = let before = before
    for i in 1:2
        before = false
    end
end

بصراحة ، أنا منزعج جدًا لأن الناس لا يقدمون هذه التعليقات إلا الآن. لقد كان هذا التغيير على درجة الماجستير لمدة عشرة أشهر.

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

هنا يصبح من الصعب بعض الشيء تعليم المبتدئين كيفية جمع الأرقام من 1 إلى 10 دون شرح الوظائف أو المتغيرات العامة.

بصراحة ، أنا منزعج جدًا لأن الناس لا يقدمون هذه التعليقات إلا الآن. لقد كان هذا التغيير على درجة الماجستير لمدة عشرة أشهر.

لكي نكون منصفين ، تم إطلاق سراح جوليا 0.7 قبل 13 يومًا. هذا تغيير جديد لمعظم مستخدمي Julia.

بصراحة ، أنا منزعج جدًا لأن الناس لا يقدمون هذه التعليقات إلا الآن. لقد كان هذا التغيير على درجة الماجستير لمدة عشرة أشهر

لسوء الحظ بالنسبة لأولئك منا الذين لا يستطيعون التعامل مع العيش على الحافة ، فهو جديد تمامًا من وجهة نظرنا.

بصراحة ، أنا منزعج جدًا لأن الناس لا يقدمون هذه التعليقات إلا الآن. لقد كان هذا التغيير على درجة الماجستير لمدة عشرة أشهر.

وبالنسبة لأولئك منا الذين تم تشجيعهم على الابتعاد عن فروع التطوير ، "إنها علامة تجارية جديدة من وجهة نظرنا".

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

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

هنا يصبح من الصعب بعض الشيء تعليم المبتدئين كيفية جمع الأرقام من 1 إلى 10 دون شرح الوظائف أو المتغيرات العامة.

هذه نقطة مهمة. بعد معرفة ماهية المشكلة حقًا ، من المدهش مدى ضآلة ظهورها بالفعل. إنها مشكلة أقل مع الكثير من كود جوليا في البرية وفي الاختبارات ، وقد كشفت عن الكثير من المتغيرات التي كانت عالمية بطريق الخطأ (في كل من اختبارات Julia Base وفقًا للعلاقات العامة الأصلية ، وقد لاحظت هذا في معظم اختبارات DiffEq). في معظم الحالات ، يبدو أن السلوك الخاطئ تمامًا ليس ما تحصل عليه (توقع تغيير في حلقة) ، ولكن توقع أن تكون قادرًا على استخدام متغير في حلقة هو ما وجدته الغالبية العظمى من حيث يظهر ذلك في تحديث البرامج النصية للاختبار إلى الإصدار 1.0. لذا فإن الشيء الجيد هو أنه في معظم الحالات يتم تقديم خطأ للمستخدم ، وليس من الصعب إصلاحه.

الشيء السيئ هو أنه من الإسهاب قليلاً أن تضطر إلى وضع global x داخل الحلقات ، والآن يختلف رمز REPL الخاص بك أيضًا عن رمز الوظيفة. ما إذا كان هذا السلوك أكثر حدسية من ذي قبل أم لا ، فهو رأي صعب لأنه كانت هناك بالتأكيد بعض الحالات الحرجة في تحديد النطاق المحلي الصعب / الناعم ، وبالتالي من السهل شرح ذلك. ولكن في الوقت نفسه ، مع وجود تفسير أكثر إيجازًا بكثير من السلوك السابق ، أصبح من السهل الآن الوصول إلى الحالات المتقدمة حيث يكون فهم قواعد النطاق أمرًا مهمًا. 🤷‍♂️.

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

global x = 5
for i = 1:5
  println(x+i)
end

يمكن أن تكون طريقة لطيفة للحفاظ على الوضوح ، وستجعل "رمز REPL بطيئًا بسبب الكرة الأرضية" أكثر وضوحًا. الجانب السلبي هو أن طرح الأشياء في دالة مرة أخرى لن يتطلب علامات global .

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

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

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

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

إذا أردنا استخدام "REPL هو نفسه داخل دالة" ، فيجب أن نفكر أيضًا في outer :

julia> i = 1
1

julia> for outer i = 1:10
       end
ERROR: syntax: no outer variable declaration exists for "for outer"

عكس:

julia> function f()
          i = 0
          for outer i = 1:10
          end
          return i
       end
f (generic function with 1 method)

julia> f()
10

بصراحة ، أنا منزعج جدًا لأن الناس لا يقدمون هذه التعليقات إلا الآن. لقد كان هذا التغيير على درجة الماجستير لمدة عشرة أشهر.

لم يستخدم الأشخاص برنامج Master للاستخدام التفاعلي أو للتدريس ، لقد استخدموه لترقية الحزم ، والتي لا تتأثر بهذا الأمر إلا بشكل ضئيل ويتم كتابتها في الغالب بواسطة مبرمجين ذوي خبرة.

(كنت أحد الأشخاص القلائل الذين قدموا ملاحظات في # 19324 ، على الرغم من ذلك ، حيث جادلت في السلوك القديم .)

تتمثل الطريقة غير الفاصلة للخروج من هذا في العودة إلى السلوك القديم (من الناحية المثالية ليس عن طريق إدخال كتل let ضمنية أو أي شيء - فقط قم باستعادة الكود القديم في julia-syntax.scm كخيار) في و REPL. أو بدلاً من ذلك ، لإتاحته في بيئات مثل IJulia التي قد ترغب في ذلك ، أضف علامة soft_global_scope=false إلى include ، include_string ، و Core.eval لاستعادة سلوك قديم.

(كنت أحد الأشخاص القلائل الذين قدموا ملاحظات في # 19324 ، على الرغم من ذلك ، حيث جادلت في السلوك القديم.)

نعم ، وأنا أقدر ذلك كثيرًا. لم يعد الأمر مهمًا الآن منذ أن اتخذنا القرار ، اتركه يخبز لمدة عشرة أشهر وقد أطلقناه الآن مع التزام طويل الأمد بالاستقرار. لذا فإن الشيء الوحيد الذي يجب فعله الآن هو التركيز على ما يجب فعله في المستقبل.

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

يعد وجود خيار للاختيار بين السلوك القديم والجديد أمرًا مثيرًا للاهتمام ولكنه يبدو متطرفًا للغاية.

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

هذا ليس ما أقوله. من الواضح أننا يجب أن نستخدم نفس الحل في كل تلك السياقات. لكن تطبيقه كنوعين مختلفين في قواعد تحديد النطاق يبدو أقل نظافة من تنفيذه كتحويل رمز مع مجموعة واحدة من قواعد تحديد النطاق. ولكن ربما تكون هذه متكافئة وظيفيًا. ومع ذلك ، يبدو أنه من الأسهل شرح قواعد تحديد النطاق الجديدة الأبسط + التحويل الذي يأخذ مدخلات من نمط REPL ويحولها قبل تقييمها.

يمكن أن يتم ذلك على أنه Meta.globalize(m::Module, expr::Expr) الذي يحول تعبيرًا عن طريق التعليق تلقائيًا على أي globals موجودة في الوحدة النمطية على أنها عامة إذا تم تعيينها داخل أي نطاق غير وظيفي عالي المستوى. بالطبع ، أعتقد أن هذا يعادل ما فعله المحلل اللغوي القديم ، ولكنه أكثر شفافية قليلاً حيث يمكنك استدعاء Meta.globalize بنفسك ومعرفة ما سيقيمه REPL.

يمكن أن يتم ذلك على أنه Meta.globalize(m::Module, expr::Expr) الذي يحول تعبيرًا عن طريق التعليق تلقائيًا على أي globals موجودة في الوحدة النمطية على أنها عامة إذا تم تعيينها داخل أي نطاق غير وظيفي عالي المستوى.

لقد بدأت بالفعل في التفكير في تنفيذ شيء كهذا منذ بضع دقائق. ومع ذلك ، يبدو أنه سيكون من الأسهل julia-syntax.jl :

  • من الممكن كتابة تحويل AST خارجي ، ولكن يبدو أن هناك الكثير من الحالات الصعبة - عليك في الأساس إعادة تنفيذ قواعد تحديد النطاق - بينما كان لدينا بالفعل الكود للحصول عليه بشكل صحيح في julia-syntax.scm .
  • إنه أمر أكثر صعوبة لشيء مثل IJulia الذي يستخدم حاليًا include_string لتقييم كتلة كاملة من التعليمات البرمجية والحصول على قيمة التعبير الأخير. لن نضطر فقط إلى التبديل إلى تحليل التعبير بالتعبير ، ولكن قد تكون هناك حاجة إلى بعض الاختراق من أجل الحفاظ على أرقام الأسطر الأصلية (لرسائل الخطأ وما إلى ذلك). (على الرغم من أنني وجدت اختراقًا لموقع ChangePrecision.jl لهذا النوع من الأشياء التي قد تعمل هنا أيضًا.)
  • ناهيك عن حالة الأشخاص الذين لديهم ملفات خارجية include ، والتي لن يتم اكتشافها من خلال تحويل AST الخاص بك.

ومع ذلك ، يبدو أنه من الأسهل شرح قواعد تحديد النطاق الجديدة الأبسط + التحويل الذي يأخذ مدخلات من نمط REPL ويحولها قبل تقييمها.

أشك بشدة في أن شرح هذا سيكون أسهل للمستخدمين الجدد من مجرد القول إن القواعد أقل انتقائية للاستخدام التفاعلي أو مقابل include بعلامة معينة.

فيما يلي مسودة أولية لتطبيق globalize(::Module, ast) : https://gist.github.com/stevengj/255cb778efcc72a84dbf97ecbbf221fe

حسنًا ، لقد اكتشفت كيفية تنفيذ دالة globalize_include_string تحافظ على معلومات رقم السطر ، وقمت بإضافتها إلى مضموني .

طريقة ممكنة (غير منقطعة) للمضي قدمًا ، إذا أحب الناس هذا النهج:

  1. قم بتحرير حزمة SoftGlobalScope.jl مع وظائف globalize إلخ.
  2. استخدم SoftGlobalScope في IJulia (وربما Juno و vscode و OhMyREPL).
  3. قم بطي وظائف SoftGlobalScope في إصدار مستقبلي من حزمة REPL stdlib واستخدمها في REPL.

أم أنه من العملي تحويله إلى REPL.jl على الفور؟ لست واضحًا تمامًا بشأن كيفية عمل تحديثات stdlib في الإصدار 1.0.

يرجى إلقاء نظرة على التنفيذ الخاص بي ، في حالة فقد شيء ما يجعله هشًا.

ألا يمكننا الحصول عليها كميزة غير افتراضية لـ REPL في 1.1؟

نسخة مكررة من # 28523 و # 28750. لأولئك الذين يقولون إنهم لا يريدون تعليم الناس عن المتغيرات العالمية ، أقترح وظائف التدريس أولاً ، قبل الحلقات for . تعتبر الوظائف أكثر أهمية على أي حال ، وهذا سيساعد في تحديد التوقعات بأنه يجب كتابة الكود في الوظائف. بينما أتفهم الإزعاج ، يمكن تحويل سلوك تحديد النطاق هذا إلى ميزة تربوية: "في الواقع ، تعد المتغيرات العالمية فكرة سيئة ، خاصة استخدامها في الحلقات ، بحيث تجعلك اللغة تنحني للخلف لاستخدامها".

إضافة ميزة غير افتراضية إلى REPL لهذا يبدو جيدًا بالنسبة لي.

JeffBezanson ، تذكر أن الكثير منا يود استخدام Julia كبديل لماتلاب إلى آخره في الدورات التقنية مثل الجبر الخطي والإحصاء. هذه ليست دورات برمجة وغالبًا ما لا يمتلك الطلاب أي خلفية عن البرمجة. ونحن لم تفعل البرمجة المهيكلة - انها تقريبا كل التفاعلي مع قصاصات قصيرة والمتغيرات العالمية.

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

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

يمتلك العديد منا من مستخدمي Julia صفرًا تمامًا من خلفية علوم الكمبيوتر (بما فيهم أنا) ، ولكن يبدو لي أن الموقف المناسب ( خاصة للطلاب) هو الرغبة في التعلم بدلاً من المطالبة بتغيير الأشياء إلى الأسوأ لاستيعاب سذاجتنا.

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

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

بالنسبة لما يستحق ، أنا أوافق على أن وجود رمز يتصرف بشكل مختلف اعتمادًا على نطاقه المرفق هو ميزة غير مرغوب فيها بشكل عام.

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

ألا يمكننا الحصول عليها كميزة غير افتراضية لـ REPL في 1.1؟

يبدو جعل خيار "عدم الفاصل عني" الخيار الافتراضي أكثر حكمة ، لا سيما الخيار الذي يستهدف المستخدمين المبتدئين بشكل مباشر. إذا كان خيارًا غير افتراضي ، فعندئذٍ بالتحديد سيكون الأشخاص الذين هم في أمس الحاجة إليه هم أولئك الذين لم يتم تمكينه (ولا يعرفون أنه موجود).

ما الذي سيفعله وضع REPL المقترح للنصوص البرمجية include ed؟ هل سيعتمد تقييم البيانات العامة على ما إذا كان وضع REPL نشطًا؟ إذا كان الأمر كذلك ، فإن IMO سيتعارض مع وعد الاستقرار 1.0.

إذا فعلنا شيئًا كهذا ، فيبدو أنه من المنطقي أن تحدد الوحدة كيفية عملها. لذلك سيكون Main وحدة "ذات نطاق بسيط" بينما تكون الوحدات الأخرى افتراضيًا وحدات "ذات نطاق صلب".

كنت مهتمًا بمعرفة ما إذا كان من الممكن تصحيح REPL للقرد لاستخدام globalize ويبدو أنه بدون بذل الكثير من الجهد (على الرغم من الاختراق تمامًا). انظر إلى الجوهر . لا يعمل هذا مع Juno (أو أي شيء آخر يستدعي Core.eval مباشرة).

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

julia> a = 0                                                                
0                                                                           

julia> for i = 1:10                                                         
         a += i                                                             
       end                                                                  
ERROR: UndefVarError: a not defined                                         
Stacktrace:                                                                 
 [1] top-level scope at .\REPL[2]:2 [inlined]                               
 [2] top-level scope at .\none:0                                            

julia> using SoftGlobalScope                                                
[ Info: Precompiling SoftGlobalScope [363c7d7e-a618-11e8-01c4-4f22c151e122] 

julia> for i = 1:10                                                         
         a += i                                                             
       end                                                                  

julia> a                                                                    
55                                                                          

(راجع للشغل: ما سبق يدور حول نفس القدر من الاختبارات كما كان!)

ماذا سيفعل وضع REPL المقترح للنصوص المضمنة؟

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

ليس من المثالي أن تكون هناك قواعد تحديد نطاق أكثر انتقاءً للكود العالمي في الملفات مقارنةً بالموجه. لكنني أعتقد أن # 19324 مقترنًا بوعد استقرار Julia 1.0 لا يترك لنا خيارات مثالية.

stevengj :

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

بعد أن درست دورات باستخدام جوليا للطلاب الذين تعرضوا مسبقًا لـ Matlab / R / ... ، أتعاطف مع هذا القلق. لكن في الوقت نفسه ، لا أعتقد أن استخدام Julia تمامًا كبديل لماتلاب وما إلى ذلك هو نهج قابل للتطبيق: كما هو موضح مرات لا حصر لها من خلال الأسئلة في الخطاب و StackOverflow ، يمكن أن يؤدي ذلك إلى عيوب في الأداء يصعب إصلاحها وفهمها ، ربما يستلزم تكلفة أكبر من الاستثمار في فهم كيفية اختلاف جوليا عن هذه اللغات الأخرى (راجع المنشورات التي تحتوي على موضوعات "لقد ترجمت هذا الرمز من Matlab وهو أبطأ بـ 10x").

أعتقد أن القضية الأساسية هي الفشل الصامت . المشكلة في حد ذاتها سهلة الفهم والإصلاح. أود أن أقترح الاحتفاظ بالسلوك الجديد ، مع إعطاء تحذير في Main (افتراضيًا ، من الممكن تعطيله).

بالنسبة لي ، المشكلة الأكبر هي عدم الاتساق الملحوظ. وهذا يعني أنني على ما يرام مع قيام جوليا بالأشياء بشكل مختلف ، ولكن:

  • لماذا يجب ألا تعمل التعليمات البرمجية التي تم لصقها من دالة في REPL؟
  • لا توجد لغة أخرى استخدمتها من قبل لديها هذا السلوك ، وهو عائق آخر للتبني
  • لماذا تتصرف كتل for بشكل مختلف عن كتل begin و if ؟ ( if أتفهم نوعًا ما ، لكن الكتلة [يجب] أن تكون كتلة.).

فيما يتعلق بالرصاصة 2 ، أعتقد أن هذه صفقة أكبر مما قد نفهمه نحن الذين استخدمنا جوليا لفترة من الوقت (وملتزمين باللغة). أستطيع أن أخبرك أنني حاليًا 0 مقابل 7 في إقناع مجموعتي بكتابة رمز في جوليا ؛ كان اثنان من هؤلاء بسبب مشكلة الحلقة for والتي لم أتمكن من شرحها لأنني لم أتعرض لها من قبل. أعتقد أنه يمكننا أن نعزو الباقي إلى افتقاري إلى الكاريزما.

أفضّل أن أتأكد من أن الكود الذي تم لصقه من دالة في REPL يتصرف بشكل مماثل للوظيفة ، وأن الحلقات for تفعل الشيء المتوقع عند استخدامها لتحليل البيانات بشكل تفاعلي ؛ أي أنها تحوِّل المتغيرات الخارجية / العالمية على وجه التحديد عند توجيهها بدون أي كلمات رئيسية خاصة.

لا أعتقد أن استخدام Julia كبديل لـ Matlab وما إلى ذلك هو نهج قابل للتطبيق: كما هو موضح مرات لا حصر لها من خلال الأسئلة على Discourse و StackOverflow ، يمكن أن يؤدي ذلك إلى عيوب في الأداء يصعب إصلاحها وفهمها ، وربما يترتب عليها تكلفة أكبر من الاستثمار في فهم كيف تختلف جوليا عن هذه اللغات الأخرى.

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

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

هل تقول أنه لا يجب علي استخدام جوليا في مقرر الجبر الخطي ؟ أو أنني يجب أن أستخدمه فقط إذا كنت مستعدًا لتدريس علوم الكمبيوتر وكذلك الجبر الخطي؟

أتفق مع stevengj على كل من المشكلة (يصبح التدريس لغير المبرمجين أكثر صعوبة) وعلى الحل (اجعل الأشياء تعمل في REPL و IDEs المختلفة). تضمين نص لا يزال يحتوي على قواعد نطاق Julia 1.0 ولكن هذا أقل أهمية ، على المرء فقط أن يكون حريصًا على أن يكون لدينا "يمكننا وضع حلقة for في دالة ثم استدعاء الوظيفة" فئة قبل "يمكننا وضع حلقة for لدينا في ملف وتضمين الملف "class.

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

هل تقول أنه لا يجب علي استخدام جوليا في مقرر الجبر الخطي؟ أو أنني يجب أن أستخدمه فقط إذا كنت مستعدًا لتدريس علوم الكمبيوتر وكذلك الجبر الخطي؟

ربما تكون قد أساءت فهم ما كنت أقوله (أو لم أعبر عنه بوضوح). كنت أتحدث عن الدورات التي تستخدم جوليا لتدريس شيء خاص بالمجال (على سبيل المثال ، قمت بتدريس الأساليب العددية لطلاب الدراسات العليا) ، وليس دورات علوم الكمبيوتر (التي ليس لدي خبرة بها).

النقطة التي كنت أحاول توضيحها هي أنه من المعقول توقع مستوى معين من الاختلاف بين جوليا واللغة X (والتي قد تكون ماتلاب) ؛ على العكس من ذلك ، فإن تجاهل هذا يمكن (ويفعل) يؤدي إلى مشاكل.

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

لقد قمت بإنشاء الحزمة (غير المسجلة) https://github.com/stevengj/SoftGlobalScope.jl

إذا كان هذا يبدو معقولاً ، يمكنني المضي قدمًا وتسجيل الحزمة ثم استخدامها افتراضيًا في IJulia (وربما إرسال ملفات PR إلى Juno إلى آخره).

النقطة التي كنت أحاول توضيحها هي أنه من المعقول توقع مستوى معين من الاختلاف بين جوليا واللغة X (والتي قد تكون ماتلاب)

بوضوح. عندما أقول "استخدم Julia بدلاً من Matlab" ، لا أعني أنني أحاول تعليمهم بناء جملة Matlab في Julia ، ولا أستهدف مستخدمي Matlab السابقين على وجه التحديد.

أنا أفضل مواجهة هذه القضايا في وقت مبكر

لا يتعلق الأمر بالاختلافات عن Matlab في حد ذاتها. أفضل حقًا ألا أتحدث عن النطاق العالمي مقابل النطاق المحلي وفائدة الكلمة الرئيسية global للتحليل الثابت في المرة الأولى التي أكتب فيها حلقة أمام الطلاب غير المتخصصين في علوم الكمبيوتر ، أو في المرة الأولى التي يلصقون فيها رمزًا من تعمل في REPL لتجربتها بشكل تفاعلي. أفضل التركيز على الرياضيات التي أحاول استخدامها في الحلقة للتعبير عنها.

لا أحد هنا يناقش نطاقًا تفاعليًا ناعمًا فقط لأن هذا ما يتوقعه مستخدمو Matlab. الاستطراد الطويل global عندما نعمل بشكل تفاعلي.)

إصلاح آخر غير مذكور هنا هو ببساطة التوقف عن عمل "من أجل" تحديد نطاق (فقط وظيفة ودعنا ننشئ نطاقًا جديدًا)

vtjnash ، أفضل تركيز هذه المناقشة على الأشياء التي يمكننا القيام بها قبل Julia 2.0. أوافق على أن امتلاك وضع تفاعلي يتصرف بشكل مختلف ليس سوى فجوة مؤقتة ، ويجب علينا التفكير بجدية في تغيير قواعد تحديد النطاق في غضون بضع سنوات.

نقطة جيدة ، وهذا يحتاج أيضًا إلى import Future.scope

(أعتقد أن هذه الوحدة النمطية / مساحة الاسم / التأثير السلوكي محجوز / موجود بالفعل)

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

قبل هذا التغيير ، يمكنك الحصول على إجابات مختلفة تمامًا (ناتجة عن تعيين نطاق مختلف) ببساطة عن طريق تشغيل نفس الرمز مرتين أو عن طريق تحريكه في ملف.

من المؤكد أن عدد الشكاوى التي رأيتها حول ذلك عمليًا (صفر) سيتضاءل أمام عدد الشكاوى والارتباك الذي ستراه (وتشاهده بالفعل) حول السلوك الحالي.

قبل هذا التغيير ، يمكنك الحصول على إجابات مختلفة تمامًا (ناتجة عن تعيين نطاق مختلف) ببساطة عن طريق تشغيل نفس الرمز مرتين

هل تقصد أنه في الكود أدناه ، يتغير a بين الحلقتين الأولى والثانية for ؟ في رأيي ، هذا سلوك متوقع وليس خطأ.

a = 0
for i = 1:5
  a += 1
end

for i = 1:5
  a += 1
end

ماذا سيفعل وضع REPL المقترح للنصوص المضمنة؟

@ mauro3stevengj أفترض إضافة وظيفة (ويقول، exec("path/to/script.jl") ) يمكن القيام به مع مجرد نسخة قاصر عثرة؟ يمكننا أيضًا تحذير exec 'من ملف آخر من نص برمجي exec ' ثم وضع بعض الرسائل التربوية هناك لحثهم على استخدام include .

بعض الأفكار التي كتبتها الليلة الماضية أثناء محاولتي التفاف رأسي حول هذه المشكلة (مرة أخرى) لمحاولة معرفة أفضل مسار للعمل قد يكون. لا يوجد استنتاج ، لكنني أعتقد أن هذا يوضح المشكلة بوضوح تام. بعد التفكير في هذه المشكلة لعدة سنوات ، لا أعتقد أن هناك أي "حل مثالي" - قد يكون هذا أحد تلك المشاكل حيث لا يوجد سوى خيارات دون المستوى الأمثل.


ينظر الناس بسذاجة إلى النطاق العالمي على أنه نوع مضحك يشمل النطاق المحلي. هذا هو السبب في أن النطاقات العالمية عملت بالطريقة التي عملت بها في Julia 0.6 وما قبلها:

  • إذا أنشأ نطاق محلي خارجي متغيرًا محليًا وتم تعيين نطاق محلي داخلي له ، فإن هذا التعيين يقوم بتحديث المتغير المحلي الخارجي.
  • إذا قام نطاق عام خارجي بإنشاء متغير عام وتم تخصيص نطاق محلي داخلي له ، فحينئذٍ قام هذا التعيين بتحديث المتغير العام الخارجي مسبقًا.

ومع ذلك ، فإن الاختلاف الرئيسي هو:

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

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


تُظهر هذه الملاحظة الأخيرة سبب وجود إشكالية في وجود نسختين مختلفتين من حلقة for في النطاق العالمي:

# file1.jl
for i = 1:5
  a += 1
end
# file2.jl
a = 1



md5-f03fb9fa19e36e95f6b80b96bac9811e



```jl
# main.jl
include("file1.jl")
include("file2.jl")
include("file3.jl")

لاحظ أيضًا أن محتويات file1.jl و file3.jl متطابقة ويمكننا تبسيط المثال من خلال تضمين نفس الملف مرتين مع معنى مختلف وسلوك مختلف في كل مرة.

حالة أخرى إشكالية هي جلسة REPL طويلة الأمد. جرب مثالا من مكان ما على الإنترنت؟ فشل لأنه حدث أن لديك متغير عام بنفس الاسم الذي يستخدمه المثال لمتغير محلي في حلقة for أو بنية مشابهة. لذا فإن الفكرة القائلة بأن السلوك الجديد هو السلوك الوحيد الذي يمكن أن يسبب الارتباك هي بالتأكيد ليست دقيقة. أوافق على أن السلوك الجديد يمثل مشكلة قابلية الاستخدام في REPL ولكني أريد فقط أن أخفف المحادثة وأن أقدم الجانب الآخر بوضوح هنا.

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

اختبار البرنامج
...
نهاية

يمكن للمرء تعليم اللغة دون الخوض في تفاصيل النطاق ومناقشة هذه النقطة فقط في النهاية.

حالة أخرى إشكالية هي جلسة REPL طويلة الأمد. جرب مثالا من مكان ما على الإنترنت؟ فشل لأنه حدث أن لديك متغير عام بنفس الاسم الذي يستخدمه المثال لمتغير محلي في حلقة for أو بنية مشابهة.

كم عدد شكاوى القوائم البريدية ومشكلات github التي تم إرسالها حول هذا الأمر من قبل المستخدمين المضطربين؟ صفر ، حسب إحصائي. لماذا ا؟ ربما لأن هذا السلوك غير مفاجئ بشكل أساسي للناس - إذا كنت تعمل في نطاق عالمي ، فأنت تعتمد على الحالة العالمية.

لذا فإن الفكرة القائلة بأن السلوك الجديد هو السلوك الوحيد الذي يمكن أن يسبب الارتباك هي بالتأكيد ليست دقيقة.

أعتقد أن هذا تكافؤ خاطئ - هناك تفاوت كبير في مستوى الارتباك المحتمل هنا. في Julia 0.6 ، يمكنني شرح مثالك للطالب في ثوانٍ: "أوه ، انظر إلى هذه الحلقة تعتمد على a ، الذي قمت بتغييره هنا." في Julia 1.0 ، أنا قلق بصدق بشأن ما سأفعله إذا كنت في منتصف محاضرة الجبر الخطي واضطررت إلى كتابة كلمة رئيسية global بشكل غامض أمام الطلاب الذين لم يسمعوا الكلمة مطلقًا "النطاق" بمعنى CS.

يجب علينا التفكير بجدية في تغيير قواعد تحديد النطاق في غضون سنوات قليلة.

بالطبع لا. هل تريد بجدية العودة إلى عالم ما قبل الإصدار 0.2 (انظر # 1571 و # 330) لنطاق الحلقة؟

في الواقع ، لم نقم مطلقًا بدعم نسخ الشفرة ولصقها بالكامل من وظيفة سطرًا بسطر في REPL. لذا يمكننا اعتبار هذا فرصة لإنجاح ذلك. على وجه التحديد ، بينما "نجح" في حلقات for ، إلا أنه لم يعمل مع الوظائف الداخلية:

x = 0
f(y) = (x=y)

داخل دالة ، سيغير f x من السطر الأول. في REPL لن تفعل ذلك. ولكن مع تحول مثل ذلك في SoftGlobalScope.jl يمكن أن ينجح. بالطبع ، ربما لا نريد ذلك افتراضيًا لأن لصق تعريفات الوظائف المستقلة لن يعمل. أول ما يتبادر إلى الذهن هو وضع REPL لتصحيح أخطاء الوظائف سطرًا بسطر.

هل تريد بجدية العودة إلى عالم ما قبل v0.2

لا ، أريد أن أعود إلى العالم 0.6. 😉

أعتقد أنني كنت أستجيب أكثر إلى:

إصلاح آخر غير مذكور هنا هو ببساطة التوقف عن عمل "من أجل" تحديد كتلة النطاق

في الواقع ، لم نقم مطلقًا بدعم نسخ الشفرة ولصقها بالكامل من وظيفة سطرًا بسطر في REPL. لذا يمكننا اعتبار هذا فرصة لإنجاح ذلك.

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

ومع ذلك ، كلما فكرت في هذه المشكلة أكثر كلما رأيت وجهات النظر المتضاربة (شخصيًا) التي أؤمن بها فيما يتعلق بما يجب أن يفعله REPL.

لكي أكون ملموسًا ، سأحبها كثيرًا إذا كانت REPL تتطابق مع قواعد تحديد النطاق لهيئة وظيفية ؛ على سبيل المثال ، المتغيرات محلية وليست عالمية ويمكنك فقط نسخ ولصق التعليمات البرمجية مباشرة من وظيفة وتعلم أنها ستعمل. أتخيل أن تنفيذًا ساذجًا سيكون شيئًا مثل التفاف الكتلة (كما ذكرنا سابقًا) للنموذج

julia> b = a + 1

يجري تحويلها إلى

let a = _vars[:a]::Float64 # extract the variables used from the backing store
    # Code from the REPL
    b = a + 1
    # Save assigned variables back to the backing store
   _vars[:b] = b
end

إذا تم إجراؤه بشكل صحيح (أي من قبل شخص يعرف ما يفعله) ، أتخيل أن هذا سيكون له عدد من الفوائد على REPL الحالي. 1. مهام سير العمل السابقة مع تحليل البيانات التفاعلية / الحساب مجرد عمل. 2. عدد أقل بكثير من المشاركات على الخطاب حيث يكون الرد الأساسي هو "التوقف عن المقارنة بالمتغيرات العالمية" - كل شيء سيكون محليًا وسريعًا جدًا! :) 3. النسخ واللصق إلى / من جسم وظيفي يعمل كما هو متوقع. 4. وظيفة workspace() like هي وظيفة تافهة إذا كان مخزن الدعم هو نوع من Dict؛ فقط امسحها. 5. تصبح الكرة الأرضية صريحة - الأشياء محلية ما لم تطلب تحديدًا أن تكون عالمية ؛ هذه ميزة كبيرة من وجهة نظري ، لا أحب إنشاء الكرات الأرضية بشكل ضمني. نقطة أخيرة بسيطة جدًا (وأنا أؤيد إضافة هذا!) ، وهذا من شأنه أن يتطابق مع سلوك Matlab مما يسهل على الأشخاص الذين ينتقلون - في Matlab REPL ، يبدو أن جميع المتغيرات محلية ما لم يتم توضيحها بشكل صريح على أنها عالمية.

حتى ساعات قليلة مضت ، بدت هذه القصة رائعة بالنسبة لي. ولكن بعد تعليق جيف حول الوظائف ، فكرت في لصق تعريفات الوظائف المستقلة وكيف أن هذا النهج سيمنع ذلك أساسًا لأن تعريفات الوظائف يجب أن تدخل في النطاق العالمي (على الأقل ، ربما يكون هذا هو المقصود) ؛ ولكن ماذا لو كان المقصود

قد ينتهي الأمر بالذهاب إلى منزل في منتصف الطريق SoftGlobalScope.jl ليكون الحل الوسط الأقل إرباكًا ولكن قلقي هو أنه مجرد مجموعة أخرى من القواعد التي يجب تذكرها (أي الأشياء تعمل في REPL ولكن ليس في جسمي الوظيفي / النطاق العالمي و والعكس صحيح).

أعتذر عن المنشور الطويل ولكن أعتقد أن هذا مهم لسهولة الاستخدام (وقد ساعدني في التفكير فيه!).

كم عدد شكاوى القوائم البريدية ومشكلات github التي تم إرسالها حول هذا الأمر من قبل المستخدمين المضطربين؟ صفر ، حسب إحصائي. لماذا ا؟ ربما لأن هذا السلوك غير مفاجئ بشكل أساسي للناس - إذا كنت تعمل في نطاق عالمي ، فأنت تعتمد على الحالة العالمية.

حسنًا ، هل قمت حقًا بإجراء دراسة منهجية لهذا الأمر؟ لابد أنني فاتني ذلك. ومع ذلك ، هذا لا يعني أن هذا السلوك ليس مصدر أخطاء أو نتائج غير متوقعة ؛ فقط بعد أن اكتشفها المستخدم ، تم التعرف عليه على أنه سلوك صحيح وبالتالي لم يطرح مشكلة / شكوى.

في Julia 1.0 ، أنا قلق بصدق بشأن ما سأفعله إذا كنت في منتصف محاضرة في الجبر الخطي واضطررت إلى كتابة كلمة رئيسية عالمية بشكل غامض

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

يبدو أن هذا النهج لم يعد ممكنًا. ولكني أتساءل عما إذا كان حقا الطريقة الصحيحة للقيام بذلك على أي حال، وفي مختلف الأمور الأثناء قد تحسنت كثيرا (رقم 265 كانت ثابتة، Revise.jl ومؤخرا Rebugger.j يكون تحسين سير العمل / تصحيح كبير).

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

مجرد ملاحظة صغيرة: في حين أن الغلاف الخاص للنطاق العالمي لـ REPL ، سيسمح بنسخ الكود من وإلى الوظائف ، فإنه لن يسمح بالنسخ واللصق إلى / من النطاق العالمي لوحدة نمطية أخرى.

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

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

(وهي ليست فقط تربوية. الحلقات في النطاق العالمي مفيدة للعمل التفاعلي. وأحد الأسباب الرئيسية التي تجعل الناس يحبون اللغات الديناميكية للحوسبة التقنية هو تسهيلهم للاستكشاف التفاعلي. ليست كل البرمجة موجهة نحو الأداء.)

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

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

أوافق على أن الأشخاص قد ارتبكوا بشأن متى وأين تحدد المهمة المتغيرات الجديدة ، لكنها كانت عادةً في الاتجاه الآخر - فقد أرادوا أن تعمل النطاقات المحلية بشكل أكثر شمولية (بدلاً من العكس) ، أو عدم التمييز بين begin و let . IIRC ، لم تكن الشكوى أبدًا أن التخصيص لمتغير عالمي في حلقة عالمية له تأثير جانبي مفاجئ يتمثل في تعديل عالمي.

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

StefanKarpinski : لدي شعور بأنه في السابق ، كان الخلط مع النطاق الناعم / الصعب ذو طبيعة نظرية (للأشخاص الذين يقرؤون الدليل) وليس عمليًا على (الأشخاص الذين يحصلون على نتائج غير متوقعة). كان هذا بالتأكيد ما كان الأمر بالنسبة لي وماذا ، على سبيل المثال ، نتائج البحث هنا تدعم هذا ؛ لقد وجدت مثالًا مضادًا واحدًا هنا .

من ناحية أخرى ، لن يربك هذا السلوك الجديد الأشخاص عند قراءة الدليل ، ولكن عند استخدام REPL. يمكن القول إن الأخير أسوأ.

SoftGlobalScope.jl هو الآن حزمة مسجلة. أعتزم تمكينه افتراضيًا (إلغاء الاشتراك) لـ IJulia ، على الأقل هذا الفصل الدراسي.

@ mauro3 ، حتى "المثال المضاد" الخاص بك يتعلق بشخص مرتبك بسبب النطاق الصعب ، وليس النطاق الناعم. من المؤكد أن عمل المزيد من النطاقات "الصعبة" في 0.7 سيخلق المزيد من هذا النوع من الارتباك.

أود أن أشير إلى أن IJulia لديها إمكانية مثيرة للاهتمام لجعل المتغيرات المحلية كتل do بشكل افتراضي. أي إذا قمت بذلك في كتلة واحدة ، فستعمل:

t = 0
for i = 1:n
    t += i
end
t

... و t يظهر فقط داخل كتلة التقييم هذه. إذا كنت تريد أن يكون مرئيًا في الخارج ، فسيتعين عليك القيام بذلك:

global t = 0
for i = 1:n
    global t += i
end
t

لقد فكرت أيضًا في نهج مشابه لـ Julia حيث تكون الكتل عبارة عن ملفات وليست وحدة نمطية. بعبارة أخرى ، يؤدي مجرد إجراء t = 0 في النطاق العلوي إلى إنشاء متغير محلي ملف بدلاً من عالمي. للإعلان عن متغير عالمي حقيقي ، ستحتاج إلى كتابة global t = 0 والذي سيكون مرئيًا في جميع أنحاء الوحدة النمطية. ربما يكون غريبًا جدًا ، لكنه حدث لي عدة مرات على مر السنين.

لدى IJulia إمكانية مثيرة للاهتمام لجعل المتغيرات كتل do محلية بشكل افتراضي

StefanKarpinski ، أعتقد أن هذا سيكون أكثر إرباكًا ، global الكلمة لجميع المتغيرات بين الخلايا غير نافعة لي - أنه يحتاج إلى المزيد من مناقشة المفاهيم نطاق من قضية مع حلقات for كنا نناقشها هنا.

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

ثم لدينا أيضًا خيار تبرير / توضيح التمييز بجعل متغيرات REPL محلية بطريقة ما إلى REPL --- أي ليست متغيرات عامة عادية ، غير متوفرة كـ Main.x . هذا مشابه جدًا لما اقترحهStefanKarpinski أعلاه ، ولكنه مشترك بين جميع كتل / خلايا الإدخال.

من وجهة نظر عملية ، فإن الحصول على هذا "الإصلاح" في REPL ليس كذلك
مهم فقط للمستخدمين المدرسين / غير المبرمجين. هذا السلوك أيضا
يجعل التصحيح التفاعلي عبر REPL (عن طريق نسخ ولصق الأجزاء) للغاية
غير عملي. يمكن أن يكون وضع التصحيح هذا مفضلًا في بعض الأحيان (حتى على ملف
مصحح أخطاء جيد و) حتى للمبرمجين ذوي الخبرة (وغالبًا ما يكون أحد
أسباب تفضيل لغة ديناميكية). بالطبع لذوي الخبرة
المبرمجين ، كونك اختياريًا لا ينبغي أن يكون مشكلة ؛ للمستخدمين المبتدئين ذلك
يفضل أن يكون الافتراضي.

تضمين التغريدة
بصفتي مبرمجًا ساذجًا ، فأنا لا أرى حقًا ما الخطأ في عرض ملف
النطاق العالمي كنوع مضحك يتضمن النطاق المحلي ، لا سيما في الديناميكي
اللغات. أنا أفهم أن الأمر ليس كذلك من وجهة نظر المترجم
صحيح بالضرورة (في جوليا) ، لكنه نموذج جميل وسهل ومفيد
لمبرمج (ساذج). (أظن أيضًا أنه قد يتم تنفيذه بالفعل بهذه الطريقة
بعض اللغات).
يبدو أيضًا أن جوليا تقدمه بهذه الطريقة للمبرمج:
ستعطي الوظيفة التالية الخطأ "لم يتم تعريفه" ، والذي
لن تنجح إذا تم وضع a = 1 قبل حلقة for.

اختبار الوظيفة ()
بالنسبة إلى i = 1:10
أ = أ + أنا
نهاية
أ = 1
إظهار أ
نهاية

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

أنا أتفق بشدة مع تجنب "العمل المخيف عن بعد" ، والكثير
تفضل تعريفًا صريحًا لاستخدام globals في الوظيفة / مكدس المكالمات
المستوى ويرغب أيضًا في الحصول على شيء مثل التحميل من ملف بتنسيق
نطاقه الخاص ، ويتطلب تعريفًا واضحًا لاستخدام المتغيرات العالمية.
على مستوى الحلقات ، سأذهب قليلاً إلى حد بعيد بالنسبة لي ، مثل
التعاريف / السياق عادة ما يكون قريبًا جدًا.
مثال الملفات الثلاثة مفتعل قليلاً (ويفشل مع المتوقع "لا
معرف "خطأ): عادةً ما تضع التعريف الأولي في نفس التعريف
ملف.
هناك خطر مخيف حقيقي في هذا (وقد عضني ذلك
بلغات أخرى) بما يشمل النطاق العالمي ، لذلك أنت
تقوم عن غير قصد بتعريف متغير عالمي قد يتداخل مع متغير آخر
الشفرة. ومع ذلك ، فإن الحاجة إلى استخدام global in the loop ليس حلاً لـ
هذه المشكلة.

wrt إلى جلسة REPL طويلة الأمد:
يحل السلوك الحالي محل وضع فشل نادر جدًا ويسهل اكتشافه
لتشغيل مثال عبر الإنترنت في REPL (تفوت نسخ / لصق ملف
التعريف الأولي للمتغير قبل الحلقة ، ولديها بالفعل
نفس المتغير المحدد عالميًا من شيء سابق) مع عدم وجوده
قادر على تشغيل مثال عبر الإنترنت بشكل صحيح إذا كان جزءًا من دالة
(بدون إضافة عالمية في كل مكان) ، وعدم حل المشكلة إذا كانت كذلك
لا (إذا كان global موجودًا بالفعل في الكود عبر الإنترنت ، فستظل تستخدم
قيمة خاطئة في المتغير الشامل الموجود بالفعل)

كان يجب أن أتابع هذا في وقت سابق ، ولكن بعد فترة وجيزة من القلق ، يبدو أن كل شيء على ما يرام.

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

في الواقع ، يعمل Rebugger (وهو بالضبط ذلك) بشكل صحيح على 1.0 فقط لأنه يفتقر إلى نطاق الإهمال 0.7 ، ولا يمكن جعله يعمل على 0.6. ومع ذلك ، يسعدني أن أكون قادرًا على التحقق من أن SoftGlobalScope.jl يبدو أنه لا يكسر ذلك. على سبيل المثال ، إذا تقدمت بعمق كافٍ إلى show([1,2,4]) فستحصل هنا:

show_delim_array(io::IO, itr::Union{SimpleVector, AbstractArray}, op, delim, cl, delim_one) in Base at show.jl:649
  io = IOContext(Base.TTY(RawFD(0x0000000d) open, 0 bytes waiting))
  itr = [1, 2, 4]
  op = [
  delim = ,
  cl = ]
  delim_one = false
  i1 = 1
  l = 3
rebug> eval(softscope(Main, :(<strong i="10">@eval</strong> Base let (io, itr, op, delim, cl, delim_one, i1, l) = Main.Rebugger.getstored("bbf69398-aac5-11e8-1427-0158b103a88c")
       begin
           print(io, op)
           if !(show_circular(io, itr))
               recur_io = IOContext(io, :SHOWN_SET => itr)
               if !(haskey(io, :compact))
                   recur_io = IOContext(recur_io, :compact => true)
               end
               first = true
               i = i1
               if l >= i1
                   while true
                       if !(isassigned(itr, i))
                           print(io, undef_ref_str)
                       else
                           x = itr[i]
                           show(recur_io, x)
                       end
                       i += 1
                       if i > l
                           delim_one && (first && print(io, delim))
                           break
                       end
                       first = false
                       print(io, delim)
                       print(io, ' ')
                   end
               end
           end
           print(io, cl)
       end
       end)))
[1, 2, 4]

لذلك فهو يعمل بشكل جيد على 1.0 (مع أو بدون softscope ). في 0.7 ، سيؤدي تقييم هذا (مع أو بدون softscope ) إلى تحقيق نتائج

┌ Warning: Deprecated syntax `implicit assignment to global variable `first``.
│ Use `global first` instead.
└ @ none:0
┌ Warning: Deprecated syntax `implicit assignment to global variable `first``.
│ Use `global first` instead.
└ @ none:0
[ERROR: invalid redefinition of constant first
Stacktrace:
 [1] top-level scope at ./REBUG:9 [inlined]
 [2] top-level scope at ./none:0
 [3] eval(::Module, ::Any) at ./boot.jl:319
 [4] top-level scope at none:0
 [5] eval at ./boot.jl:319 [inlined]
 [6] eval(::Expr) at ./client.jl:399
 [7] top-level scope at none:0

لذا فإن 0.7 / 1.0 هي بالتأكيد خطوة للأمام ، وإذا كان softscope يجعل بعض الأشياء أسهل دون كسر الوظائف المهمة فهذا رائع.

لذلك ، فإن الشاغل الأكبر هو ببساطة كيفية اعتراض ذلك بشكل مناسب دون تخزين الحزم الأخرى (https://github.com/stevengj/SoftGlobalScope.jl/issues/2).

timholy ، لا تلمس SoftScope وسيطات استدعاءات الماكرو (نظرًا لعدم وجود طريقة لمعرفة كيفية إعادة كتابة الماكرو) ، لذا فإن :(<strong i="6">@eval</strong> ...) محمي.

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

المتغير المحلي (الخارجي) a موجود ، لكن لم يتم تعيينه بعد. إذا حاولت الحلقة التخصيص إلى a قبل قراءتها ، فستكون المهمة مرئية بالخارج أيضًا.

بشكل عام ، يعد إنشاء ارتباط متغير وتعيين قيمة له خطوات منفصلة.

ما هو الخط الزمني في هذا؟ يبدو أنه سيكون تحسنًا كبيرًا في سهولة استخدام المستخدم. وفي هذا الوقت "الحرج" لـ Julia مع إصدار 1.0 ، قد يبدو من المفيد إصلاح هذا في أسرع وقت ممكن (بالطريقة التي اقترحها Jeff أعلاه) ووضع علامة على إصدار Julia جديد أو إصدار REPL. (آسف على تعليق كرسي الذراع هذا ، لأنني بالتأكيد لن أصلح هذا!)

تضمين التغريدة
كنت سأجادل أنه في حين أن هذا صحيح (للتنفيذ / المترجم) ، فإن مبرمج جوليا الساذج لا يمكنه رؤية أي سلوك مختلف عن نموذجه المفاهيمي الأبسط (يبدأ المتغير في الوجود في لحظة تحديده). لسوء الحظ ، أنت على حق ، لن يعطي الكود التالي خطأ ، بينما سيعطي خطأ إذا تركت a = 2 في النهاية
اختبار الوظيفة ()
بالنسبة إلى i = 1:10
أ = 1
نهاية
println (أ)
أ = 2
نهاية
سأشرح لسوء الحظ: يمكنني فهم السلوك (لأنني عملت مع اللغات المترجمة من قبل) ولكن ما زلت أجده محيرًا وغير متوقع. ما مدى سوء الأمر بالنسبة لشخص لديه خبرة في البرمجة النصية فقط أو جديد في البرمجة. أيضًا ، وجدت بعض التعليمات البرمجية التي توضح السلوك ، ولا أرى تطبيقًا مفيدًا (ربما يمكنك مساعدتي هناك)

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

أنا و jeffbezanson في إجازات طال انتظارها (لا ينبغي أن أقرأ هذا). يمكننا معرفة ما يجب القيام به في غضون أسبوع أو نحو ذلك.

derijkp ، بينما يتم تقدير التعليقات ، فإن قواعد تحديد النطاق لا تخضع لنقاش أو مراجعة أوسع. الشيء الوحيد المطروح على الطاولة هو التقييم التفاعلي ذي الغلاف الخاص. تعد حزمة SoftGlobalScope بالفعل تنفيذًا تجريبيًا ممتازًا وقد تكون مجرد مسألة إنشاء هذا الجزء من Base واستخدامه في REPL.

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

نعم ، أستطيع أن أصدق أن هذا يتعارض مع حدس بعض الناس. لكن يمكنك التحسين خلال الدقائق العشر الأولى فقط من استخدام لغة معينة. السؤال الحقيقي هو ، ما مدى صعوبة تعليم / تعلم كيفية عمله ، وأي تصميم سيوفر الوقت على المدى الطويل (بجعل اللغة أبسط ، وتسهيل تطوير الأدوات ، وما إلى ذلك)؟

(بالاتفاق مع الكثير مما ورد أعلاه حول تعديل سلوك REPL)
أود أن أرى REPL بطريقة لا تؤدي إلى سؤال stackoverflow
وستكون الأفضل عاجلاً لأن العديد من العيون الجديدة تنظر إلى جوليا

أوافق ... وأعتقد أيضًا أن قواعد تحديد النطاق لا يجب أن تتغير بالضرورة ، فقط جميع الواجهات التفاعلية (على سبيل المثال ، إدخال عنصر تحكم REPL و Jupyter و Juno)

هذا لا يتعلق فقط بتعلم المبتدئين لقاعدة جديدة. إذا لم تتمكن من نسخ أجزاء من التعليمات البرمجية ولصقها في REPL و jupyter وما إلى ذلك وأيضًا في الوظائف ، فهذا يمثل مصدر إزعاج كبير للمبرمجين المتوسطين أيضًا.

بالطبع ، أتفق أيضًا مع الملصقات الأخرى ... مع المبتدئين ، سيأخذون أجزاء التعليمات البرمجية التي يرونها داخل الوظائف ، وينسخون I إلى نصوص ، ويشعرون بالارتباك تمامًا عندما لا يكون لها نفس السلوك عند نسخها داخل وظيفة ، في جونو ، البديل ، وجوبيتر. سيكون هناك 100 سؤال تبادل مكدس والتي تنزل إلى نفس المشكلة. سيحصل المبرمجون المتوسطون على جميع أنواع الحلول المحلية مع التفاف في كتل let ، وما إلى ذلك مما سيزيد من إرباك الأمور

سيكون هناك 100 سؤال تبادل مكدس والتي تنزل إلى نفس المشكلة. سيحصل المبرمجون المتوسطون على جميع أنواع الحلول المحلية مع التفاف في كتل let ، وما إلى ذلك مما سيزيد من إرباك الأمور

ربما ، ولكن في هذه المرحلة يكون هذا افتراضيًا (أيضًا OP الخاص بالسؤال المرتبط يسأل عن الأساس المنطقي لقاعدة تحديد النطاق ، بدلاً من الخلط بشأنه).

أيضًا ، بينما أحترم تجربة التدريس لكل من لديه مخاوف بشأن هذا الأمر ، فإن ما إذا كان هذا يمثل مشكلة كبيرة في الفصل الدراسي هو أمر سيخبرنا به الوقت.

يبدو أن السائل قد اختلط عليه الأمر: "أتساءل عما إذا كان هذا بديهيًا لمستخدمي جوليا المبتدئين. لم يكن ذلك بديهيًا بالنسبة لي ..."

يبدو أن السائل قد أربكه:

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

ربما ، ولكن في هذه المرحلة يكون هذا افتراضيًا

لقد أجبت بالفعل على العديد من الأسئلة المتعلقة بهذا الأمر في stackoverflow ، معظمها من قبل مستخدمين جدد ، وأكثر من ذلك في الحياة الواقعية (آخر سؤال بالأمس فقط ، من مستخدم Matlab ، الذي رأى هذا على أنه محظور).

سيكون هناك 100 سؤال تبادل مكدس والتي تنزل إلى نفس المشكلة.

في "وقت فراغي" ، قمت بإضافة علامات scope و scoping و global-variables لأسئلة SE. أتوقف فقط بسبب ضيق الوقت ، وليس بسبب عدم وجود المزيد.

الخلاصة بعد الكثير من النقاش بما في ذلك الفرز: سنقوم بتضمين شيء على غرار SoftGlobalScope في القاعدة ونستخدمه في REPL وجميع سياقات التقييم التفاعلية الأخرى. أشار JeffBezanson إلى أن الطريقة التي يتم بها تنفيذ ذلك هي في الأساس نفس الطريقة التي تم بها تنفيذ النطاق المرن سابقًا ، لذلك إلى حد ما نحن نقترب من دائرة كاملة. الفرق هو أنه لا يوجد الآن سلوك نطاق في الوحدات النمطية أو البرامج النصية ، فقط في السياقات الشبيهة بـ REPL. أعتقد أيضًا أن _شرح_ النطاق الناعم كإعادة كتابة المصدر أوضح من محاولة التمييز بين النطاقات الصلبة والناعمة (التي لم أوضحها جيف أبدًا ، ربما أشير إليها).

هاتان العبارتان تربكانني قليلاً لأنهما تبدوان متناقضين بعض الشيء:

واستخدامها في REPL وجميع سياقات التقييم التفاعلية الأخرى

لا يوجد سلوك نطاق في البرامج النصية [...] ، فقط في السياقات الشبيهة بـ REPL.

هل هذا يعني أن الوحدة Main لها أحيانًا نطاق بسيط (على سبيل المثال في موجه REPL) وأحيانًا نطاق صلب (لنقل عندما julia -L script.jl )؟ ألن يكون من المنطقي أن نقول إن Main دائمًا ما يكون له نطاق ضعيف؟ ويمكن للوحدة أن تشترك في النطاق الناعم بمقدار using SoftGlobalScope ؟

(أظن) لا يمكن تغيير قواعد تحديد النطاق في البرامج النصية لأنها ستكون غير متوافقة مع الإصدارات السابقة ، أي أنها تخلف الوعد بأن أي كود مكتوب لـ 1.0 سيعمل على أي إصدار 1. *. أنت محق في أن نفس مشكلة تحديد النطاق لـ REPL تنطبق أيضًا على البرامج النصية (مستخدم ساذج في حيرة من سبب عدم عمل الكود الخاص به بشكل صحيح عند تشغيله كبرنامج نصي). تتمثل إحدى طرق حل / تخفيف هذه المشكلة دون عدم توافق كبير في إضافة خيار إلى julia cmdline لاستخدام softscope (أو بديل) ، على سبيل المثال julia -f programfile ، وإظهار هذا الخيار في أي وصف / برنامج تعليمي يحتمل أن يقوم به المبتدئ تصادف.
أرى أيضًا بديلاً محتملاً لـ softscope والذي قد يكون له بعض المزايا (على الرغم من أنني ربما أغفل بعض العيوب): ماذا لو كان ملف (نص يسمى) سيقدم دائمًا نطاقه المحلي الخاص: قواعد تحديد النطاق ستكون متوافقة تمامًا مع تلك الموجودة في مع توقعات الكثير من المستخدمين. سيؤدي أيضًا إلى إزالة الكثير من التزامات الأداء مع المستخدمين الجدد:
لا مزيد من الكرات الأرضية غير الضرورية (يجب تحديد الكرات الأرضية بشكل صريح) ، وقد يتم تجميع الكود
(كم مرة كان عليك أن تقول لوضع كل شيء في وظيفة ، وتجنب استخدام globals؟)

لقد ضربت هذا للتو وكنت محيرًا تمامًا لأكون صادقًا ، لأنني لم أره من قبل بأي لغة أخرى. أخطط لتقديم دورة Julia الاختيارية لمستخدمي R المتقدمين في uni في وقت لاحق من هذا العام بمجرد أن تستقر الأمور ، وسيصل طلابي إلى هذا في اليوم 0 عندما يبدأون في كتابة الأشياء بشكل عشوائي في REPL. وحقيقة أن الحلقات for تتصرف بشكل مختلف عن عبارات if فقط إلى فرك الملح في الجرح ، مهما كان ذلك منطقيًا من حيث تحديد النطاق. النطاق الداخلي للوظائف صعب بما يكفي لجعل طلاب علم الأحياء يفهمون ، فكرة الاضطرار إلى شرح _ وإن كان متصورًا_ تناقضات صارخة فيها في REPL / في نص / في حلقة for / في عبارة if (لأن هذا ما نتحدث عنه) حول هنا) بطريقة تختلف عن أي لغة أخرى على وجه الأرض تجعلني حزينًا للغاية.

أنا أتفهم وعد التوافق مع الإصدارات السابقة الذي تم تقديمه ، ولكن الحصول على هذا العمل - كما هو متوقع من قبل كل شخص غير مسئول عن الخدمة على هذا الكوكب (ومعظم الأشخاص الذين أظنهم) _ يبدو وكأنه إصلاح خلل وليس مشكلة توافق مع الإصدارات السابقة - نحن لا نقول أن كل علة سوف تتكاثر إلى الأبد نحن؟ من الواضح أن إصلاح REPL ضروري ، لذلك من الرائع أن تقترح هذا ، ولكن بعد ذلك تضطر إلى التوضيح ، لا يمكنك نسخ نص في REPL وتتوقع أن يبدو السلوك نفسه سيئًا أو أسوأ من المشكلة الأصلية.

من فضلك ، من فضلك ، يرجى التفكير في التعامل مع هذا على أنه إصلاح خلل ودفعه مع البرامج النصية بالإضافة إلى REPL - حتى لو كان هناك تبديل للانتقال إلى السلوك "القديم" - والقيام بذلك في أقرب وقت ممكن في 1.0.1.

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

لا أعتقد أن التعامل مع هذا على أنه "إصلاح خلل" أمر وارد ، لأنه سيؤدي إلى كسر عقد الاستقرار 1.0. ومع ذلك ، يبدو من المعقول بالنسبة لي استخدام softscope للبرامج النصية التي تعمل باستخدام julia -i (أي الوضع "التفاعلي").

(أي أنه سيكون هناك علامة --softscope={yes|no} وستكون افتراضيًا لقيمة isinteractive .)

سيتعين علينا النظر في اختيار وضع البرنامج النصي.

في هذا الصدد ، ليس من الجنون بالنسبة لي تعيين الإعداد الافتراضي إلى --softscope=yes لأي "نص برمجي" ، أي لـ julia foo.jl ، وتشغيل قواعد النطاق "الصارمة" للوحدات و include (عند هذه النقطة يجب أن تضع معظم الأكواد في الوظائف).

في هذا الصدد ، ليس من الجنون بالنسبة لي الافتراضي --softscope = نعم لأي "نص برمجي" ،

الذي - التي. الآخر الذي يجب مراعاته بجدية هو جونو. تذكر أن الأشخاص سيقومون <shift-enter> خلال الكود الخاص بهم للقيام بالتطوير التفاعلي (خاصة عند العمل مع اختبارات الانحدار) ثم يتوقعون لاحقًا أن يكونوا قادرين على تشغيل نفس الملف. هل يجب أن يهم ما إذا كانت الشفرة في @testset أم لا (والتي أعتقد أنها قد تقدم نطاقًا)؟ سيكون الأمر محيرًا جدًا للمستخدم إذا تغير نفس النص عندما يكون في @testset مقابل ليس عند استخدام تكامل Atom ، ويتعارض مع عمل ] test أيضًا.

من المؤكد أنه يبدو لي أن أفضل حل هو أن النطاق الصعب هو مجرد شيء للاشتراك ، حيث إذا كان كل استخدام آخر (بما في ذلك include داخل البرامج النصية) يستخدم softscope ما لم تقل غير ذلك .

تختلف عن كل لغة أخرى على وجه الأرض

هل تريد كتابة var x = 0 لتقديم كل متغير؟ سيؤدي ذلك أيضًا إلى "إصلاح" هذا الأمر ، ويكون مثل اللغات الأخرى.

نحن لا نقول أن كل خطأ سيتم إعادة إنتاجه إلى الأبد نحن

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

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

اسمحوا لي أن أحاول مرة أخرى تقديم تفسير لهذا قد يكون مفيدًا لتجنب الهوس والهستيريا والمذابح التي يراها الأشخاص في الفصل:

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

ربما يمكن تحسين ذلك ؛ نرحب بالاقتراحات. أعلم أنك تفضل ألا تحتاج إلى أي نوع من التفسير على الإطلاق. فهمت ذلك. لكن الأمر لا يبدو سيئًا للغاية بالنسبة لي.

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

أنا موافق. يبدو لي وكأنه صداع في التدريس والتواصل.

على سبيل المثال ، قد يكون النطاق الصعب داخل الوحدات النمطية فقط منطقيًا.

فقط حتى أفهم: إذا كان لدي برنامج نصي قصير (ليس في وحدة نمطية!) في ملف .jl قمت بنسخه من دفتر IJulia ، فعندئذ إذا قمت بتشغيل هذا الرمز في REPL مباشرة أو في shift- أدخل في Juno ، فسوف يتصرف باستمرار كنطاق ناعم ... ولكن إذا قمت بنسخه بدلاً من كتلة module ، فسوف يصرخ في وجهي بخصوص globals؟ ولكن إذا قمت بنسخ هذا الرمز داخل وظائف داخل وحدة نمطية ، فيجب أن يعمل.

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

هل تريد كتابة var x = 0 لتقديم كل متغير؟ سيؤدي ذلك أيضًا إلى "إصلاح" هذا الأمر ، ويكون مثل اللغات الأخرى.

لا ، لا أفضل! لكن لغات البرمجة النصية التي تحتوي على REPL نادرًا ما تفعل ذلك (على سبيل المثال ruby ​​، ​​python ، R ، ...) ، تتصرف مثل Julia v0.6.

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

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

لاحظ أيضًا أنه ليس فقط "_المتغيرات التي تقدمها في REPL أو في المستوى الأعلى ، خارج أي شيء آخر ، هي عالمية _" و "_المتغيرات التي يتم تقديمها داخل الدوال والحلقات تكون محلية_" ، إنها أيضًا المتغيرات الموجودة في عبارات if في REPL أو في المستوى الأعلى عالمي لكن المتغيرات في @testset محلية. ينتهي بنا المطاف في حفرة أرنب من "جربها واعمل بنفسك سواء كان محليًا أو عالميًا ، حظًا سعيدًا".

ومع ذلك ، أتفق مع jlperla - فإن الاقتراح القائل بأن "النطاق الصعب داخل الوحدات فقط قد يكون منطقيًا" يبدو جيدًا تمامًا بالنسبة لي! الوحدات النمطية هي مفهوم متقدم بما فيه الكفاية مرة أخرى ... إذا كان النطاق الناعم يعمل مع REPL والنصوص ، فلا بأس بذلك تمامًا.

لا نريد شيئًا معقدًا عن بُعد مثل نطاق التأثير على الناس ...
في المستوى الأعلى عالمية لكن المتغيرات في @testset محلية

ما أحاول الوصول إليه هو أنني أشعر أن وصفًا بسيطًا للعالمي مقابل المحلي كافٍ للتدريس في المرحلة المبكرة - لا تحتاج حتى إلى قول كلمة "نطاق" (لا يحدث على الإطلاق في توضيحي أعلاه). عندما تعرض فقط بعض التعبيرات والحلقات البسيطة في REPL ، فأنت لا تعلم الناس عن مجموعات الاختبارات ولا تحتاج إلى قائمة شاملة لسلوك تحديد النطاق لكل شيء في اللغة.

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

ويكفي استخدام سطر بسيط في "عالمي مقابل محلي".

في عالم بدأ فيه الجميع في كتابة كل التعليمات البرمجية الخاصة بهم من البداية ، سأوافق تمامًا.

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

ثم يبدأ الطلاب في التساؤل عن سبب قيام for بإنشاء هذا النطاق الذي يحتاجون إلى القلق بشأنه وليس الأشياء الأخرى ...

ينتهي بنا المطاف في حفرة أرنب من "جربها واعمل بنفسك سواء كان محليًا أو عالميًا ، حظًا سعيدًا".

اختبار سريع: في جوليا 0.6 ، هو x عالميًا أو محليًا:

for i = 1:10
    x = i
end

الإجابة هي أنه لا توجد طريقة لمعرفة ذلك ، لأنه يعتمد على ما إذا كان قد تم تحديد x عالميًا من قبل. الآن ، يمكنك أن تقول على وجه اليقين أنها محلية.

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

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

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

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

هذه المحادثة مقفلة الآن ولا يمكن التعليق إلا على مرتكبي جوليا.

JeffBezanson ، ما هي خطة تنفيذ الدلالات التي اقترحتها في سلسلة الخطاب هذه ، مبدئيًا فقط في REPL والاشتراك في مكان آخر؟

يبدو أنك تخطط لوضع ذلك مباشرة في الكود المنخفض ( julia-syntax.scm ) ، بدلاً من إعادة كتابة النحو على SoftScope.jl؟ أو هل تفضل الحصول عليها كإعادة كتابة بناء الجملة أولاً (تعديل SoftScope للقاعدة المقترحة وتحويلها إلى stdlib) ، وتأجيل وضعها في الكود المنخفض لإصدار Julia لاحقًا؟

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

القضايا ذات الصلة

tkoolen picture tkoolen  ·  3تعليقات

StefanKarpinski picture StefanKarpinski  ·  3تعليقات

StefanKarpinski picture StefanKarpinski  ·  3تعليقات

manor picture manor  ·  3تعليقات

omus picture omus  ·  3تعليقات