Треки
/
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

Вказівки

Ми працюємо в IT-службі підтримки й хочемо вдосконалити систему тікетів, щоб вона працювала ефективніше та давала статистику для нашого керівника.

Тікет має статус (new, in progress...), автора (його визначають за іменем користувача та ідентифікатором співробітника), його можна призначити IT-працівнику, і він містить історію коментарів.

Ось чотири завдання, які допоможуть удосконалити нашу поточну систему тікетів.

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. Виявити тікети, призначені команді розробників

Деякі тікети потрібно ескалювати до Аліси, Боба або Чарлі з команди розробників. Важливо стежити за ними, щоб переконатися, що робота просувається.

Визначмо допоміжну функцію assignedToDevTeam, яка перевіряє, чи призначено тікет одному з членів команди розробників.

Використаймо деструктуризацію в аргументі функції, щоб дістати запис із типу Ticket і потрібне нам поле. Потім скористаймося однією конструкцією case, щоб перевірити, чи призначено тікет Алісі, Бобу або Чарлі: рекурсивне зіставлення зі зразком дістане їхні імена користувачів, а літеральне зіставлення зі зразком їх збіжить.

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

4. Призначити тікети IT-працівникам

Іноді купу тікетів потрібно перепризначити іншим IT-працівникам.

Визначмо функцію 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 вправ та справжнє наставництво від людей, і все це безкоштовно.