ال

اللاشيء في Julia

1 تمرين

نبذة عن اللاشيء

توفّر كثير من اللغات وسيلة مثل null أو none للدلالة على قيمة غير موجودة. ولأن Julia مصمَّمة للتعامل مع كميات ضخمة من البيانات (التي غالبًا ما تكون غير منظّمة)، فلها صور متعددة من الغياب.

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

nothing

إذا كانت القيمة غير موجودة فعلًا، فإنها تُمثَّل بـ nothing. وهذا على الأرجح أقرب ما يشبه ما تفعله C بـ NULL أو Python بـ None.

julia> n = nothing

julia> isnothing(n)
true

julia> typeof(n)
Nothing

إذن nothing قيمة وحيدة من النوع Nothing، ويمكننا اختبارها.

من الاستخدامات الشائعة لـ nothing أن يكون قيمة إرجاع (أو لا قيمة) للدوال التي تُستخدم فقط من أجل آثارها الجانبية (الطباعة، أو إعداد الشبكة، أو أي شيء من هذا القبيل).

missing

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

وهكذا فإن missing قيمة نائبة، تنبّه البشر إلى أنهم بحاجة إلى اتخاذ قرار بشأن كيفية التعامل مع هذه الفجوة في البيانات.

julia> mv = [1, 2, missing]
3-element Vector{Union{Missing, Int64}}:
 1
 2
  missing

julia> typeof(mv)
Vector{Union{Missing, Int64}} (alias for Array{Union{Missing, Int64}, 1})

julia> ismissing.(mv)  # broadcast function, displays as 1 for true, 0 for false
3-element BitVector:
 0
 0
 1

قليل من اللغات الأخرى تضم هذه الميزة بشكل مدمج، لكن أقرب نظائرها NA في R أو NULL في SQL.

نوع المتجه في المثال أعلاه هو Union{Missing, Int64}، وهو يشبه إلى حد ما أنواعًا مثل Option أو Maybe في لغات أخرى.

عادةً ما تُرجع التعبيرات missing افتراضيًا إذا كانت هناك قيم missing. وإذا أردت تجاهل هذه القيم، فاستخدم دالة skipmissing() لجعل ذلك صريحًا:

julia> mv = [1, 2, missing]
3-element Vector{Union{Missing, Int64}}:
 1
 2
  missing

julia> sum(mv)  # missing in, missing out
missing

julia> skipmissing(mv)
skipmissing(Union{Missing, Int64}[1, 2, missing])

julia> collect(skipmissing(mv))
2-element Vector{Int64}:
 1
 2

julia> sum(skipmissing(mv))  # functions like sum() can work with iterators
3

ولأن skipmissing تُنشئ مُكرِّرًا، فغلّفها بـ collect() إذا كنت بحاجة إلى متجه.

أحيانًا يكون من المفيد استبدال قيم missing بقيمة افتراضية ما. وتفيد ماكرو @coalesce() في ذلك، إذ تُرجع أول قيمة غير مفقودة (أو missing إن لم يكن هناك شيء آخر).

julia> str = ["I", "exist", missing]
3-element Vector{Union{Missing, String}}:
 "I"
 "exist"
 missing

julia> [@coalesce(s, "-") for  s in str]
3-element Vector{String}:
 "I"
 "exist"
 "-"

NaN

اختصارًا لـ «ليس عددًا»، تشير NaN إلى مشكلة حسابية في الحالات التي كان يُتوقع فيها عدد.

julia> v = [0, 1, -1]
3-element Vector{Int64}:
  0
  1
 -1

julia> v / 0
3-element Vector{Float64}:
 NaN
  Inf
 -Inf
 
julia> sum(v / 0)
NaN

أي حساب على بيانات تتضمن قيمة NaN سيعطي نتيجة NaN.

لا توجد حاليًا دالة خاصة لإزالة قيم NaN، لكن دالة filter() القياسية تستطيع فعل ذلك ببساطة. لن تُنسخ إلى مصفوفة النتيجة إلا القيم التي يتحقق فيها شرط معيّن بقيمة true:

julia> filter(!isnan, [1, 2, NaN])
2-element Vector{Float64}:
 1.0
 2.0

البيانات غير المعرّفة

هذا جانب يُحتمل أن تستخدمه بوتيرة أقل. وتشمل هذه الحالات:

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

الحصول على نتيجة undef عند محاولة الوصول إلى قيمة هو حالة خطأ، يُشار إليها عادةً بـ UndefRefError.

تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة

تعلّم اللاشيء