Julia: كان للبث وظيفة واحدة (مثل البث عبر التكرارات والمولد)

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

كان من المدهش أن نجد أن broadcast لا يعمل مع التكرارات

dict = Dict(:a => 1, :b =>2)
<strong i="7">@show</strong> string.(keys(dict)) # => Expected ["a", "b"]
"Symbol[:a,:b]"

هذا بسبب إرجاع Any Broadcast.containertype Any https://github.com/JuliaLang/julia/blob/413ed79ec54f3a754ac8bc57c1d29835d17bd274/base/broadcast.jl#L31
مما أدى إلى الرجوع على: https://github.com/JuliaLang/julia/blob/413ed79ec54f3a754ac8bc57c1d29835d17bd274/base/broadcast.jl#L265

يؤدي تحديد containertype ليكون Array لهذا المكرر إلى مشاكل في استدعاء size عليه ، لأن broadcast لا يقوم بالتحقق من واجهة المكرر iteratorsize(IterType) .

map يحل هذه المشكلة بالرجوع map(f, A) = collect(Generator(f,A)) والذي قد يكون أكثر منطقية من التعريف الحالي broadcast(f, Any, A) = f(A)

broadcast

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

هذا متعمد. broadcast للحاويات ذات الأشكال ، والافتراضيات هي معاملة الكائنات على أنها مقاسات. map للحاويات بدون أشكال ، وافتراضي لمعاملة الكائنات على أنها مكررات.

على سبيل المثال ، يعامل broadcast السلاسل على أنها "حجمية" ، بينما map يتكرر مع الأحرف.

ال 69 كومينتر

هذا متعمد. broadcast للحاويات ذات الأشكال ، والافتراضيات هي معاملة الكائنات على أنها مقاسات. map للحاويات بدون أشكال ، وافتراضي لمعاملة الكائنات على أنها مكررات.

على سبيل المثال ، يعامل broadcast السلاسل على أنها "حجمية" ، بينما map يتكرر مع الأحرف.

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

أيضًا ، كما أشار stevengj من قبل: يجب أن يكون هناك فرق بين map و broadcast ، إذا لم يكن الأمر كذلك ، فما الهدف من وجود كليهما.

stevengj لكن http://docs.julialang.org/en/release-0.5/manual/interfaces/#interfaces

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

pabloferz الفرق الرئيسي بين map و broadcast هو معالجة الحجميات. الآن تعريف العدد القياسي قابل للنقاش وأود أن أقول إن كل شيء يحتوي على length(x) > 1 لا ينبغي اعتباره عددًا.

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

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

جريت في هذا أيضا. بدءًا من # 16769 حيث أبحث عن طريقة إلى fill! مصفوفة بتقييمات متكررة لوظيفة (بدلاً من قيمة ثابتة) ، اعتقدت أن بناء الجملة النقطي قد يؤدي بالفعل إلى الحيلة. ولكن عندما يعمل a = zeros(2, 3); a .= [rand() for i=1:2, j=1:3] ، فإن (سيكون) أرخص a .= (rand() for i=1:2, j=1:3) لا ؛ هذا المولد هو HasShape() ، لكن ليس لديه بالفعل إمكانية فهرسة. أنا خفيف جدًا في فهم كيفية عمل البث / بناء الجملة ، ولكن هل من المفيد هنا الحصول على سمة لقدرات الفهرسة؟ هناك PR (# 22489) لذلك بالفعل ...

rfourquet ، يمكنك عمل a = zeros(2, 3); a .= rand.()

نعم ، لكن يجب أن أكون أكثر دقة: أريد استخدام وظيفة تحصل على المؤشرات كمعلمات ، مثل a .= (f(i, j) for i=1:2, j=1:3) .

ما هي عيوب أبعاد البث لمكررات HasShape ؟ هذا يبدو وكأنه شيء طبيعي يجب القيام به.

nalimilan ، للوهلة الأولى أعتقد أن هذا سيكون معقولًا وربما سهل التنفيذ نسبيًا. سيتم كسر ذلك يجب أن يتم بواسطة 1.0.

إحدى المشكلات المحتملة في هذا الأمر هي أن أجهزة التكرار HasShape لا تدعم بالضرورة getindex ، وهذا قد يجعل من الصعب تنفيذها؟

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

إحدى المشكلات المحتملة في هذا الأمر هي أن متكررات HasShape لا تدعم بالضرورة getindex ، وقد يجعل ذلك من الصعب تنفيذها؟

كما قلت أعلاه ، لديّ علاقات عامة برقم # 22489 للسماح بالفهرسة في التكرارات ، إذا كان هذا يمكن أن يساعد.

ما الذي يجب القيام به لـ 1.0 حتى نتمكن على الأقل من تحسين السلوك في 1.x؟

شكرًا nalimilan على طرح هذا الموضوع ، أردت أن أفعل ذلك أيضًا. إذا كان السماح لمولدات HasShape على الجانب الأيمن من تعبير البث غير ممكن للتنفيذ لـ 1.0 ، فهل يجب أن نجعل هذا خطأ الآن ، بدلاً من التعامل مع المولدات على أنها مقاسات؟ بحيث يمكن تمكين هذا في 1.x.

: +1: يوصي Triage بجعل هذا خطأ (الخيار الآمن) أو استدعاء collect عليه (إذا كان من السهل القيام بذلك).

يعامل map كل الوسائط على أنها حاويات ، ويحاول تكرارها جميعًا. في عالمي المثالي ، سيكون broadcast متشابهًا ، ومعالجة جميع وسائطه لها أشكال يمكن بثها ، وإعطاء خطأ إذا لم يتم تحديد size سبيل المثال. سأشير إلى أنه يمكن التعامل مع أي قيمة على أنها عدد قياسي في البث عن طريق تغليفها بـ fill ، مما ينتج عنه صفيف 0-d:

julia> fill("a")
0-dimensional Array{String,0}:
"a"

julia> fill([2])
0-dimensional Array{Array{Int64,1},0}:
[2]

هل تقترح حقًا معاملة جميع الحجميات كحاويات بشكل افتراضي؟ هذا لا يبدو عمليا جدا.

بالنظر إلى الكيفية التي يمكننا بها دعم أي متكرر ، أو مجرد إلقاء خطأ لهم حتى ندعمهم ، يبدو أننا سنحتاج إلى طريقة لتحديد التكرارات في BroadcastStyle . هذا غير ممكن حاليًا ، نظرًا لأن Base.iteratorsize يُرجع HasLength حتى بالنسبة للكميات مثل Symbol . يمكننا تقديم سمة Base.isiterable (والتي يمكن أن تكون مفيدة لأشياء أخرى) ، أو جعل Base.iteratorsize افتراضيًا إلى NotIterable (وهو أمر منطقي أيضًا لأن لديك HasLength كإعداد افتراضي دائمًا مفاجئًا بعض الشيء ، إذا كان غير ضار).

(حالة صعبة للمناقشة المستقبلية: UniformScaling .)

timholy منذ أن قمت بإعادة تصميم broadcast ، هل من اقتراحات؟

JeffBezanson ، الهدف الكامل من broadcast هو أن تكون قادرًا على "بث" الحجميات لمطابقة الحاويات ، على سبيل المثال القيام بـ ["bug", "cow", "house"] .* "s" ----> ["bugs", "cows", "houses"] . هذا يختلف جوهريًا عن سلوك map .

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

يجب أن يكون من الممكن إعلان نوع معين ليكون حاوية لـ broadcast خلال تحديد طريقة مناسبة عليه ، لكنني أعتقد أن الوضع الافتراضي يجب أن يستمر في التعامل مع الكائنات على أنها مقاييس.

في العلاقات العامة غير ذات الصلة (https://github.com/JuliaLang/julia/pull/25339) ، اقترح Keno استخدام applicable(start, (x,)) لمعرفة ما إذا كان x متكررًا أم لا. هل يجب أن نستخدم نفس الأسلوب هنا؟ سأجد أنه من الواضح أن يكون لديك تعريف أكثر وضوحًا للمكررات (استنادًا إلى Base.iteratorsize أو على سمة) ، ولكن استخدام start أيضًا أمر منطقي.

يمكن أن يكون لدينا سمة صريحة افتراضية هي applicable(start, (x,)) ؛ من شأنه أن يسمح بتجاوزه إذا لزم الأمر.

لقد قدمت # 25356 لتوضيح الحلول الممكنة وعيوبها.

من مثالstevengj ["bug", "cow", "house"] .* "s" ----> ["bugs", "cows", "houses"] ، لا يبدو أن التكرار كافٍ ، نظرًا لأن السلاسل قابلة للتكرار ولكنها تعمل مثل الحجميات هناك. إذا كنت بحاجة إلى تحديد سمة على أي حال ، فقد يكون من الأفضل الاستمرار في طلب الاشتراك للبث ، بدلاً من إضافة متطلبات إلى جميع التكرارات.

لحسن الحظ ، يُرجع keys(dict) الآن AbstractSet ، لذلك إذا أضفنا سمة بث لـ AbstractSet ، فسيتم إصلاح المثال في OP. يمكننا أيضًا إضافة خطأ لبث Generator للقبض على بعض الحالات الشائعة.

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

نعم ، أدركت عند إعداد العلاقات العامة أن المجموعات ليست في الحقيقة أفضل مثال على التكرارات التي يجب أن تدعم البث. أشياء مثل Generator و ProductIterator هي حالات أكثر إثارة للاهتمام.

ربما يكون الجواب (محاولة) بث مكررات لها HasShape ، والاستمرار في التعامل مع كل شيء آخر على أنه مقاييس؟ لن تصلح OP ، لكنها أنيقة جدًا بخلاف ذلك.

فكرة عشوائية أخرى: ربما يجب أن يكون البث عبر وسيطة واحدة (كما في string.(x) ) حالة خاصة تشبه map ، نظرًا لأن توافق الشكل ليس مشكلة؟

ربما يكون الجواب (محاولة) بث مكررات لها HasShape ، والاستمرار في معاملة كل شيء آخر على أنه عدد قياسي؟ لن تصلح OP ، لكنها أنيقة جدًا بخلاف ذلك.

لست متأكدًا من أن لدينا سببًا قويًا لاستبعاد مكررات HasLength . نحن ندعم البث عبر المجموعات (التي لا تطبق size ) ، فلماذا لا نتعامل مع التكرارات عديمة الشكل مثل tuples؟ على سبيل المثال ، سيكون من المنطقي تمامًا أن تكون قادرًا على استخدام نتيجة keys(::OrderedDict) مع broadcast . إذا لم ندعمها ، فسيغري الناس بتعريف مكرراتهم على أنها HasShape فقط لتكون قابلة للاستخدام مع broadcast (وصيغة النقطة اللطيفة).

على حد تعبير ستيف ،

broadcast للحاويات ذات الأشكال

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

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

ربما يستطيع stevengj أن يطور لماذا يعتقد أن broadcast يجب أن يدعم الحاويات ذات الشكل فقط؟ هل ستدعم النظر إلى المجموعات على أنها عددية أيضًا؟

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

من حيث المبدأ ، سأدعم استخدام مكررات HasShape كحاويات في broadcast . المشكلة الرئيسية ، كما أشرت أعلاه ، هي أن وجود HasShape لا يضمن أن getindex يعمل.

المشكلة الرئيسية ، كما أشرت أعلاه ، هي أن وجود HasShape لا يضمن عمل getindex

هل سيساعد شيء مثل # 22489 ، أي امتلاك سمة مكرر تشير إلى ما إذا كان المكرر قابلاً للفهرسة؟

هل سيساعد شيء مثل # 22489 ، أي امتلاك سمة مكرر تشير إلى ما إذا كان المكرر قابلاً للفهرسة؟

ولكن عندئذٍ سيتم دعم التكرارات القابلة للفهرسة فقط باستخدام broadcast ؟ يبدو هذا مقيدًا للغاية ، حيث سيكون من المفيد جدًا أن تكون قادرًا على القيام بأشياء مثل string.(itr, "1") لأي شيء متكرر (على سبيل المثال ، نتيجة keys(::OrderedDict) ) ، والفهرسة غير مطلوبة لتنفيذ ذلك. أعتقد أنه من الأفضل أن نخطئ لجميع التكرارات التي لا تدعم الفهرسة في 0.7 / 1.0 ، ونحاول دعمها في الإصدارات اللاحقة. ليس من المفيد جدًا التعامل مع التكرارات على أنها عددية على أي حال. ثم يمكننا تنفيذ أي سلوك نريده في إصدارات 1.x.

stevengj أوافق على حججك فيما يتعلق بالسلاسل HasLength أنها tuples؟ لم أقرأ أي تبرير لهذا حتى الآن.

nalimilan ، أميل إلى الاعتقاد بأن متكررات + hasshape القابلة للفهرسة فقط هي التي يجب أن تدعمها broadcast . محاولة حشر المكرر العام في هذه الوظيفة يخلط معناه أكثر من اللازم - في مرحلة ما ، يجب عليك فقط استخدام map .

سيكون من المفيد جدًا أن تكون قادرًا على القيام بأشياء string.(itr, "1") لأي شيء متكرر… ليس من المفيد جدًا التعامل مع التكرارات على أنها مقاسات على أي حال.

حالة السلاسل تتعارض مع هذا - الوسيطة "1" نفسها قابلة للتكرار في مثالك. أطنان من الأشياء قابلة للتكرار (على سبيل المثال ، PyObject s في PyCall تحدد start وما إلى ذلك) ، بما في ذلك أشياء مثل المجموعات غير broadcast حيث يكون مفهوم

لاحظ أيضًا أن # 24990 سيجعل map أسهل مما هو عليه الآن ، على سبيل المثال ، ستتمكن من القيام بـ map(string(_,"1"), itr) .

nalimilan ، أميل إلى الاعتقاد بأن متكررات + hasshape القابلة للفهرسة فقط هي التي يجب دعمها بالبث. محاولة حشر المكرر العام في هذه الوظيفة يخلط معناه أكثر من اللازم - في مرحلة ما ، يجب عليك فقط استخدام الخريطة.

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

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

(FWIW، PyObject لا يبدو وكأنه مثال عظيم بالنسبة لي كما IIUC انها تطبق بروتوكول التكرار لمجرد أنها لا تعرف مسبقا ما إذا كان سيتم التفاف بيثون مكرر أم لا. PyObject الواضح أن getfield لتظهر ككائن Julia قياسي. المجموعات هي مثال أكثر جوليانية.)

يمكننا إضافة سمة لمكررات HasShape القابلة للفهرسة ، كما تم اقتراحه في مكان آخر.

يحب الفرز فكرة جعل البث يتكرر عبر جميع الوسائط (مثل الخريطة) ، وإضافة حرف عامل التشغيل (مثل عمل const & = Ref كما هو مقترح سابقًا في قضية أخرى ، أو ربما ~ ) لوضع علامة صراحة 0-د الحجج.

vtjnash ، ماذا يعني ذلك حتى بالنسبة HasShape ؟ هل تقصد أنك تريد البث للتكرار على أشياء مثل الأوتار والمجموعات؟ تنفيذ broadcast مرتبط ارتباطًا وثيقًا بـ getindex … هل فكرت في كيفية تنفيذه بدون getindex ، خاصةً للجمع بين الوسائط ذات الأبعاد المختلفة؟

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

يبدو أن السمة IteratorAccess من العلاقات العامة https://github.com/JuliaLang/julia/pull/22489 يمكن تكييفها / إعادة استخدامها لاكتشاف التكرارات القابلة للفهرسة. من الضروري أيضًا معرفة التكرارات القابلة للفهرسة (وبالتالي يجب تنفيذ keys ) من أجل https://github.com/JuliaLang/julia/pull/24774.

نسخة إلى: rfourquet

👍 يوصي الفرز بجعل هذا خطأ (الخيار الآمن) أو استدعاء جمع عليه (إذا كان من السهل القيام بذلك).

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

السلوك التالي يبدو جيدًا:

  • بشكل افتراضي ، حاول تكرار وبث كل وسيطة.
  • أعط خطأ إذا لم ينجح ذلك لأي سبب من الأسباب.
  • مرر Ref(x) أو [x] لإجبار x على معاملته كقياس.
  • أضف سمة يمكن تعريفها للسماح لنوع جديد بأن يتم التعامل معه على أنه عدد قياسي بدلاً من إعطاء خطأ. لاحظ أنه لا يجب استخدام هذا للاختيار بين التكرار وليس التكرار. إنه فقط لتحويل الخطأ إلى سلوك قياسي.

هل يمكنك توضيح الملاحظة المتعلقة بالنقطة الأخيرة (ربما بمثال)؟ لست متأكدًا مما يعنيه وجود السمة ولكن لا يتم استخدامها للاختيار بين التكرار مقابل عدم التكرار.

لذا ، يعني "حاول تكرار كل وسيطة وبثها" أننا بحاجة إلى تحديد BroadcastStyle لإرجاع Scalar() لجميع أنواع غير المجموعة (لا سيما Number ، Symbol و AbstractString )؟ هذا يبدو مثل "السمة" التي ذكرتها الرصاصة الأخيرة.

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

هذا يبدو مثل "السمة" التي ذكرتها الرصاصة الأخيرة

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

إذن "حاول تكرار وبث كل وسيطة" يعني ضمنيًا أننا بحاجة إلى تعريف BroadcastStyle لإرجاع Scalar () لجميع الأنواع غير المجمعة (خاصة Number و Symbol و AbstractString)؟ هذا يبدو مثل "السمة" التي ذكرتها الرصاصة الأخيرة.

لا ، كل الأنواع الفرعية العددية لـ Number تكرر نفسها ، وبالتالي فهي جيدة. سنحتاج إلى تعريفه للرمز. سيعمل AbstractString كمجموعة.

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

ما زلت أعتقد أن البث يجب أن يتعامل مع مكررات HasShape فقط كحاويات ؛ وهذا يتفق مع تصميم البث منذ البداية. ما هو الخطأ في ذلك؟

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

أيضًا ، سأكون سعيدًا تمامًا للتخلي عن جزء "السمة" من الاقتراح. لا أحد يشكو منه

julia> map(string, [1,2], :a)
ERROR: MethodError: no method matching start(::Symbol)

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

لقد خطر ببالي ذلك ، لكن يبدو أنه من المحير جعل حجة واحدة حالة خاصة.

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

ما زلت أعتقد أن البث يجب أن يتعامل مع مكررات HasShape فقط كحاويات ؛ وهذا يتفق مع تصميم البث منذ البداية. ما هو الخطأ في ذلك؟

stevengj ما هو الخطأ IMHO هو أنه يجعل بعض العمليات لا تعمل عندما يمكن تنفيذ سلوك معقول تمامًا: تعامل مع مكررات HasLength تمامًا مثل Tuple ، وهو حاليًا ذو غلاف خاص. حتى لو لم ندعمهم الآن ، أود أن أترك إمكانية دعمهم مفتوحة في مرحلة ما في 1.x.

لا أحد يشكو منه

جوليا> الخريطة (سلسلة ، [1،2] ،: أ)
خطأ: MethodError: لا توجد طريقة تطابق start (:: Symbol)

JeffBezanson OTC ، أنا أؤيد السلوك الحالي لـ broadcast ، والذي يكرر :a حسب الحاجة. يمكن أن يكون هذا النوع من الأشياء مفيدًا جدًا ، على سبيل المثال إعادة تسمية سلسلة من أعمدة DataFrame . هل تقترح تغيير broadcast بحيث يظهر خطأ مثل map ؟

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

إنه سهل ، لكنه غير مريح تمامًا. أتفق مع stevengj على أنه يجب بث Number قابلة للتكرار ، فلن يكون الإزعاج مرئيًا دائمًا ، ولكن كما يوضح المثال Symbol ، لن يكون مفيدًا جدًا بشكل عام. Char واحدًا آخر ، وستعاني العديد من الأنواع المخصصة المحددة في الحزمة أيضًا من هذا (وينتهي الأمر بتعريف BroadcastStyle كـ Scalar() ).

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

اقتراح جيف في https://github.com/JuliaLang/julia/issues/18618#issuecomment -360594955 به مساحة للسماح للبث بمعاملة Symbol و Char كأنواع "عددية" - هم فقط بحاجة إلى الاشتراك في السلوك. بشكل افتراضي سيكونون خطأ ، لأنهم لا يطبقون start .

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

هناك ثؤلول هنا ، رغم ذلك. نظرًا لأن الأرقام قابلة للتكرار (حتى HasShape ) ، فسيتم التعامل معها على أنها حاويات صفرية الأبعاد. هذا يعني أنه ، إلى استنتاجه المنطقي ، 1 .+ 2 != 3 . سيكون fill(3, ()) بدلاً من ذلك.

تحرير: في محاولة لتجنب عرقلة الخيط أكثر ، انتقل إلى الخطاب:

https://discourse.julialang.org/t/lazycall-again-sorry/8629

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

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

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

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

  • يمكن أن يكون map مرتبطًا بشدة ببروتوكول التكرار - يبدو أنه من الصحيح أنه يمكننا إنشاء out = map(f, iterable) كسول لأي iterable مثل first(out) مثل مثل f(first(iterable)) ، ويبدو لي أن هذه العملية البطيئة العامة قد تكون مفيدة.
  • يمكن أن يكون broadcast مرتبطًا بشدة بواجهة الفهرسة - يبدو أنه من الصحيح أنه يمكننا إنشاء out = broadcast(f, indexable) كسول بحيث يكون out[i] هو نفسه f(indexable[i]) ، و يبدو لي أن هذه العملية البطيئة العامة يمكن أن تكون مفيدة. من الواضح أن broadcast مع مدخلات متعددة لا يزال بإمكانه القيام بكل الأشياء الفاخرة التي يقوم بها الآن. لغرض البث ، ستكون المقاييس هي تلك الأشياء التي لا يمكن فهرستها (أو الفهرسة بشكل تافه مثل Number و Ref و AbstractArray{0} ).

أشعر أيضًا أنه سيكون من المرغوب فيه أن تقوم الوسيطة الواحدة map والحجة الواحدة broadcast بأشياء متشابهة جدًا للمجموعات القابلة للتكرار والفهرسة. ومع ذلك ، فإن حقيقة أن التكرار AbstractDict يعرض أشياء مختلفة عن getindex يبدو أنه يحظر توحيدًا لطيفًا هنا. : frowning_face: (تبدو أنواع المجموعات الأخرى لدينا جيدة)

(بالنسبة لي ، حقيقة أن أشياء مثل السلاسل يجب أن يتم تغليفها بشكل صريح مثل ["bug", "cow", "house"] .* ("s",) لا تبدو وكأنها تفسد الصفقات هنا. لدي نفس المشكلة عندما أريد أن أفكر في ناقل ثلاثي باعتبارها "نقطة ثلاثية الأبعاد مفردة" وليس من الصعب التعامل معها (xref # 18379)).

أوافق على أن يكون broadcast للحاويات القابلة للفهرسة ، لكنني أعتقد أنه يجب أن يكون قابلاً للفهرسة على التوالي ، مما يستبعد السلاسل. على سبيل المثال ، يعطي collect(eachindex("aαb🐨γz")) [1, 2, 4, 5, 9, 11] ، والذي سيلعب بشكل سيئ مع أي تطبيق broadcast على أساس الفهرسة.

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

لست متأكدًا من أن الفهارس المتتالية تمثل قيدًا جيدًا - على سبيل المثال ، سيكون للقواميس مؤشرات عشوائية.

ومع ذلك ، لا يستطيع broadcast(f, ::String) إنشاء String ويضمن أن تظل مؤشرات المخرجات كما هي مع مؤشرات الإدخال نظرًا لأن عرض أحرف UTF-8 قد يتغير تحت f ( يجب أن يتحول إلى شيء مثل AbstractDict{Int, Char} لتقديم هذا الضمان ، والذي لا يبدو مفيدًا حقًا!). أود أن أقول تقريبًا أن مؤشرات String تشبه إلى حد كبير "الرموز" للبحث السريع بدلاً من المؤشرات المهمة لغويًا (على سبيل المثال ، يمكنك التحويل إلى سلسلة UTF-32 مكافئة وستتغير المؤشرات).

لا أمانع إذا جعلنا سلوك البث مشتركًا عبر السمة ؛ أنا أقول فقط أن تخيل كيف يتصرف broadcast(f, ::Any) هو طريقة جيدة لتوجيه تنفيذ أشياء مثل broadcast(f, ::AbstractDict) (وسأجيب بطبيعة الحال على السؤال الذي طرحته في # 25904 ، أي البث عبر قيم القاموس وليس أزواج القيمة الرئيسية).

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

لقد قمت ببث الأشياء التي يجب التعامل معها على أنها عددية _ طوال الوقت_.

ما هي أنواع تلك الأشياء؟

ممكن ان يكون اي شيء. على سبيل المثال ، في الحزمة التي تحدد نموذج التحسين ، اكتب Model ونوع متغير القرار Variable ، قد يكون لديك x::Vector{Variable} الذي تريد الحصول على قيم له بعد حل النموذج model باستخدام دالة value(::Variable, ::Model)::Float64 . في السابق ، كان يمكنك القيام بذلك مثل:

value.(x, model)

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

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

باختصار ، هناك أربعة خيارات تتجنب الخطأ الاحتياطي غير الصحيح:

  1. تتطلب _ everything_ تنفيذ طريقة تصف كيفية البث
  2. افتراضيًا في معاملة الأشياء على أنها حاويات والخطأ / الإهمال لغير الحاويات.

    • سنحاول فقط iterate كائنات غير معروفة وهذا سيخطئ بالنسبة للكميات

    • هناك نوعان من فتحات الهروب للكميات - يمكن للمستخدمين لفها في موقع اتصال ويمكن لمؤلفي المكتبة الاشتراك في البث غير المغلف الذي يشبه العددية.

  3. افتراضيًا يتم التعامل مع الأشياء على أنها مقاييس وخطأ للحاويات غير المعروفة

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

    • لن يكون هناك سوى فتحة هروب واحدة متاحة للحاويات المخصصة حتى لا تخطئ: مؤلفو مكتبتهم يختارون البث بشكل صريح. يبدو هذا عكسيًا تمامًا بالنسبة لوظيفة هدفها الأساسي هو العمل مع الحاويات.

  4. حدد applicable(iterate, …) وبدّل السلوكيات وفقًا لذلك

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

الخيار 1 أسوأ للجميع ، والخيار 2 هو الوضع الراهن ، والخيار 3 عكسي ، والخيار 4 شيء لم نفعله من قبل ومن المحتمل أن يكون هناك أخطاء.

أعتقد أن بعض المناقشة يجب أن تكون قد حدثت خلف الكواليس ، لكنني لست مقتنعًا بالحجج التي رأيتها في هذا الموضوع وفي https://github.com/JuliaLang/julia/pull/25356 مقابل nalimilan وظائف stevengj .

لن يكون هناك سوى فتحة هروب واحدة متاحة للحاويات المخصصة حتى لا تخطئ: مؤلفو مكتبتهم يختارون البث بشكل صريح. يبدو هذا عكسيًا تمامًا بالنسبة لوظيفة هدفها الأساسي هو العمل مع الحاويات.

هذه هي نقطة الخلاف الرئيسية. بالنسبة لي ، يبدو أنه في كل رمز جوليا # of iterator types << # of types that should be treated as scalars in a broadcast situation < # of broadcast calls . لذلك أفضل إذا كان عدد المرات التي يجب القيام فيها بشيء "إضافي" يتناسب مع عدد أنواع المكرر ، بدلاً من عدد مكالمات البث. وإذا حدد مؤلف مكتبة مكررًا ، فليس من غير المعقول تمامًا مطالبتهم بتعريف طريقة أخرى ، في حين أنه من غير المعقول تمامًا مطالبة كل مؤلف حزمة بتعريف Base.broadcastable(x) = Ref(x) لجميع الأنواع غير القابلة للتكرار من أجل تجنب القبيح (IMHO) Ref s في نسبة عالية من broadcast للمكالمات.

وأنا أعلم أن وجود طريقة واحدة لتنفيذ لتحديد التكرار هو لطيف، ولكنها ليست أن هناك الكثير من العمل لتنفيذ واحد أكثر لأي سمة جديدة، أو لجعله اللازمة لتحديد Base.iteratorsize لمكرر الجديد (و التخلص من مشكلة HasLength الافتراضية). يمكن عندئذٍ أن تستند الطريقة الاحتياطية broadcastable على تلك السمة. أو ، إذا كنت مغرمًا حقًا بتعريف التكرار بطريقة واحدة ، فيمكنك (إزالة ما بعد الإيقاف) أن يكون لديك هذه السمة الصريحة الافتراضية إلى applicable(iterate, ...) كما في https://github.com/JuliaLang/ julia / issues / 18618 # issuecomment -354618742 ، وقم ببساطة بتجاوز هذا الإعداد الافتراضي إذا لزم الأمر. لا يزال من الممكن أيضًا معالجة حالات الزاوية مثل String من خلال broadcastable إذا رغبت في ذلك.

هذا هو تصميم 0.6 ، الذي أدى إلى هذه المشكلة و # 26421 و # 19577 و # 23197 و # 23746 وربما أكثر - البحث عن هذا صعب.

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

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

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

تلك هي الحجج الرئيسية. بقدر ما قبح المرجع ، أنا أتفق تماما. حل هناك # 27608.

عادل بما يكفي. ليس لدي أي حجج ضربة قاضية أو حلول سحرية لتلك المشاكل ، و https://github.com/JuliaLang/julia/pull/27608 سيحسن الأمور.

tkoolen كان لدي نفس المخاوف وحالة الاستخدام .

mbauman الحجج الواردة أعلاه قد لا تكون مقنعة تمامًا. فيما يلي سؤالان يجب إكمالهما بشكل أكبر:

1) سيكون من الممكن جعل broadcastable واجهة مطلوبة لأي تكرار.
سيكون هذا منهجيًا تمامًا ، وسيجبر المطورين على التفكير فيه
كيف يجب أن يتصرف مكررهم أثناء البث.
إن التوصية بتعيينها على أنها collect(x) ستجعل الانتقال سهلاً نسبيًا في معظم الحالات.
لن يكون هناك أي خسارة في الأداء ، أليس كذلك؟

2) لذلك يتلخص الأمر في الإرادة لوجود خطأ في f.(x) إذا تم بث x أنه عدد قياسي.
لماذا لا يظهر تحذير / خطأ linter لـ f.(x, y, z) ، مثل "كل وسيطات 'f' بث كسلسلة"؟

على أي حال ، قد يكون من الحكمة إصلاح # 27563 (على سبيل المثال بواسطة # 27608) والسماح للمستخدمين باللعب به قبل 1.0.
[تم إصدار 0.7 و 1.0.0-rc1.0 بدون إصلاح].

على أي حال ، قد يكون من الحكمة إصلاح # 27563 (على سبيل المثال بواسطة # 27608) والسماح للمستخدمين باللعب به قبل 1.0.
[تم إصدار 0.7 و 1.0.0-rc1.0 بدون إصلاح].

أعتبر أنك فاتتك الأخبار التي تفيد بإصدار 1.0 .

StefanKarpinski غاب عن ذلك ، في الواقع. مبروك لجميع المطورين ، جوليا مذهلة ، استمروا!

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

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

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

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

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

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

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