كان من المدهش أن نجد أن 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
للحاويات ذات الأشكال ، والافتراضيات هي معاملة الكائنات على أنها مقاسات. 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, ())
بدلاً من ذلك.
تحرير: في محاولة لتجنب عرقلة الخيط أكثر ، انتقل إلى الخطاب:
اقتراح جيف في # 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
أو مجموعة مكونة من عنصر واحد. هذا ليس بالأمر المستحيل ، لكنه يجعل الحالة الشائعة أقل أناقة من أجل دعم نمط استخدام غامض نسبيًا ، في رأيي.
نعم ، أرى وجهة نظرك ، وأنا أوافق على أنها مزعجة في مثل هذه المواقف. ومع ذلك ، كان السلوك القديم إشكاليًا تمامًا - فقد كان أحد تلك الأشياء "الاحتياطية الافتراضية خطأ بالتأكيد في بعض الحالات".
باختصار ، هناك أربعة خيارات تتجنب الخطأ الاحتياطي غير الصحيح:
iterate
كائنات غير معروفة وهذا سيخطئ بالنسبة للكمياتiterate
ألقى خطأ في الأسلوب. هذا بطيء وغير مباشر.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 غاب عن ذلك ، في الواقع. مبروك لجميع المطورين ، جوليا مذهلة ، استمروا!
التعليق الأكثر فائدة
هذا متعمد.
broadcast
للحاويات ذات الأشكال ، والافتراضيات هي معاملة الكائنات على أنها مقاسات.map
للحاويات بدون أشكال ، وافتراضي لمعاملة الكائنات على أنها مكررات.على سبيل المثال ، يعامل
broadcast
السلاسل على أنها "حجمية" ، بينماmap
يتكرر مع الأحرف.