المسارات
/
Elm
Elm
/
التمارين
/
تذكرة، من فضلك!
تذكرة، من فضلك!

تذكرة، من فضلك!

تمرين تعلّمي

مقدمة

مطابقة الأنماط

تتيح مطابقة الأنماط كتابة كود تفريعي معبّر، ويوفّر التفكيك ربطًا أنيقًا للقيم بالمتغيرات.

مطابقة الأنماط البسيطة

تستطيع مطابقة الأنماط ربط القيم بالمتغيرات، أو تجاهلها باستخدام المحرف البديل _، وذلك بالاستعانة بجملة case.

type Entity = Alien | Stranger (Maybe String) | Friend { name: String }

hello : Entity -> String
hello entity =
    case entity of
        -- Custom type variant
        Alien -> "Hello, you are not from around here are you?"
        -- Binding to a litteral value nested in Stranger
        Stranger (Just nametag) -> "Hello, erm... " ++ nametag ++ "."
        -- Discarding Friend's data
        Friend _ -> "Hi!"
        -- All other cases
        _ -> "Hello stranger!"

التفكيك

يستطيع التفكيك ربط القيم في ارتباطات let، وفي وسائط الدوال، وبالطبع في تعبيرات case، متى كان للبيانات شكل واحد ممكن فقط.

pairSum : ( Int, Int ) -> Int
pairSum pair =
    -- Destructuring of a pair in a 'let' binding
    let ( x, y ) = pair
    in x + y

-- Destructuring in the function argument
pairSum : ( Int, Int ) -> Int
pairSum ( x, y ) = x + y

-- Custom type containing a single variant
type Container = Box String

-- Destructuring in the function argument
unbox : Container -> String
unbox (Box str) = str

-- Destructuring combined with pattern matching
unboxMaybe : Maybe Container -> Maybe String
unboxMaybe maybeContainer =
    case maybeContainer of
        Nothing -> Nothing
        Just (Box "42") -> Just "The answer to the universe!"
        Just (Box str) -> Just str

يمكن أيضًا استخدام التفكيك مع السجلات، أو مع الكلمة المفتاحية as.

type alias Circle =
    { radius : Float
    , center : ( Float, Float )
    }

perimeter : Circle -> Float
perimeter { radius } =
    2 * pi * radius

left : Circle -> Float
left { radius, center } =
    -- the pair center cannot be pattern matched directly in the function argument
    -- so we do it in a 'let' statement
    let ( x, _ ) = center
    in x - radius

-- using the 'as' keyword to bind both the fields and the whole record
smaller : Float -> Circle -> Circle
smaller reduction ({ radius } as circle) =
    if reduction < radius then
        { circle | radius = radius - reduction }
    else
        circle

التعليمات

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

للتذكرة حالة (جديد، قيد التنفيذ...)، ومنشئ (يُعرَّف باسم مستخدم ومعرّف موظف)، ويمكن إسنادها إلى موظف في تقنية المعلومات، وتحتوي على سجل من التعليقات.

إليك أربع مهام ستحسّن نظام التذاكر الحالي.

1. اكتشاف التعليقات الفارغة

التعليقات الفارغة تزدحم بها الواجهة ولا تقدّم أي معلومات، لذلك تريد تصفيتها.

عرّف دالة مساعدة emptyComment تأخذ زوجًا من المستخدم والتعليق وتُرجع True للتعليقات الفارغة.

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

emptyComment ( User "Alice", "" )
-- => True

2. حساب عدد التعليقات من المنشئ

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

عرّف numberOfCreatorComments التي تأخذ تذكرة وتُرجع عدد التعليقات التي أضافها منشئ التذكرة.

استخدم التفكيك في وسيط الدالة لاستخراج السجل من نوع Ticket، في الوقت نفسه الذي تستخرج فيه الحقول التي تحتاجها من السجل. ثم فكّك createdBy في ارتباط let حتى تتمكن من عدّ التعليقات ذات الصلة. استخدم دوال List لإجراء العدّ، واستخدم التفكيك في وسيط الدالة لدالة مجهولة لفصل زوج المستخدم والتعليق.

numberOfCreatorComments
numberOfCreatorComments
    (Ticket
        { status = Closed
        , createdBy = ( User "Chiaki", 1 )
        , assignedTo = Nothing
        , comments = [ ( User "Chiaki", "Never mind, fixed it." ) ]
        }
    )
-- => 1

3. اكتشاف التذاكر المُسندة إلى فريق التطوير

بعض التذاكر يجب تصعيدها إلى Alice أو Bob أو Charlie من فريق التطوير. من المهم متابعة هذه التذاكر للتأكد من أنها تحرز تقدمًا.

عرّف دالة مساعدة assignedToDevTeam تتحقق مما إذا كانت التذكرة مُسندة إلى أحد أعضاء فريق التطوير.

استخدم التفكيك في وسيط الدالة لاستخراج السجل من نوع Ticket وكذلك الحقل الذي تحتاجه. ثم استخدم عبارة case واحدة للتحقق مما إذا كانت التذكرة مُسندة إلى Alice أو Bob أو Charlie، وذلك باستخدام مطابقة الأنماط العودية لاستخراج أسماء المستخدمين الخاصة بهم ومطابقة الأنماط الحرفية لمطابقتها.

assignedToDevTeam
    (Ticket
        { status = InProgress
        , createdBy = ( User "Bill", 2 )
        , assignedTo = Just (User "Alice")
        , comments = [ ( User "Bill", "What's an 'undefined'?" ) ]
        }
    )
-- => True

4. إسناد التذاكر إلى موظفي تقنية المعلومات

أحيانًا يلزم إعادة إسناد مجموعة من التذاكر إلى موظفي تقنية معلومات آخرين.

عرّف دالة assignTicketTo لمساعدتك في ذلك. تستقبل الدالة وسيطين: مستخدمًا تُسند إليه التذكرة وتذكرة. إذا كانت حالة التذكرة New، فأسندها إلى المستخدم الجديد وغيّر الحالة إلى InProgress. أما بالنسبة للحالات الأخرى، فأعد إسناد التذكرة إلى المستخدمين الجدد ببساطة، باستثناء التذاكر ذات الحالة Archived التي لا ينبغي تعديلها على الإطلاق.

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

assignTicketTo (User "Danny")
    (Ticket
        { status = New
        , createdBy = ( User "Jesse", 3 )
        , assignedTo = Just (User "Alice")
        , comments = [ ( User "Jesse", "I've been waiting for 6 months!!" ) ]
        }
    )
-- => Ticket
--        { status = InProgress
--        , createdBy = ( User "Jesse", 3 )
--        , assignedTo = Just (User "Danny")
--        , comments = [ ( User "Jesse", "I've been waiting for 6 months!!" ) ]
--        }
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
Elm Exercism

مستعد لبدء تذكرة، من فضلك!؟

سجّل في Exercism لتتعلّم وتتقن Elm عبر 28 مفهومًا110 تمارين، وإرشاد بشري حقيقي، وكل ذلك مجانًا.