Percursos
/
Elm
Elm
/
Exercícios
/
Bilhete, por favor!
Bilhete, por favor!

Bilhete, por favor!

Exercício de aprendizagem

Introdução

Correspondência de padrões

A correspondência de padrões permite escrever código com ramificações expressivas, e a desestruturação traz uma ligação elegante de valores a variáveis.

Correspondência de padrões simples

A correspondência de padrões pode ligar valores a variáveis ou descartá-los com o caráter universal _, com recurso à instrução 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!"

Desestruturação

A desestruturação pode ligar valores em ligações let, em argumentos de funções e, claro, em expressões case, sempre que só existe uma forma possível para os dados.

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

A desestruturação também pode ser usada com registos, ou com a as palavra-chave.

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

Instruções

Fazes parte do helpdesk de TI e queres melhorar o sistema de tickets para que seja mais eficiente e fornecer estatísticas ao teu gestor.

Um ticket tem um estado (novo, em curso...), um criador (identificado por um nome de utilizador e um ID de funcionário), pode ser atribuído a um funcionário de TI e contém um historial de comentários.

Aqui estão quatro tarefas que vão melhorar o teu sistema de tickets atual.

1. Detetar comentários vazios

Os comentários vazios sobrecarregam a interface e não trazem informação nenhuma, por isso queres filtrá-los.

Define uma função auxiliar emptyComment que recebe um par utilizador/comentário e devolve True para os comentários vazios.

Usa a desestruturação para extrair o utilizador e o comentário diretamente no argumento da função. Ignora o utilizador, uma vez que não precisas dessa informação.

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

2. Contar o número de comentários do criador

A tua gestora quer ter estatísticas sobre o envolvimento dos utilizadores no processo dos tickets. Pede-te para verificares quantos comentários são adicionados pelo criador do ticket.

Define numberOfCreatorComments, que recebe um ticket e devolve o número de comentários adicionados pelo criador do ticket.

Usa a desestruturação no argumento da função para extrair o registo do tipo Ticket, ao mesmo tempo que os campos de que precisas do registo. Depois, desestrutura o createdBy numa ligação let para poderes contar os comentários relevantes. Usa funções do List para fazer a contagem e usa a desestruturação no argumento da função de uma função anónima para separares o par utilizador/comentário.

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

3. Detetar tickets atribuídos à Dev Team

Alguns tickets têm de ser escalados para a Alice, o Bob ou o Charlie da Dev Team. É importante estar atento a esses para garantir que estão a progredir.

Define uma função auxiliar assignedToDevTeam que verifica se um ticket está atribuído a um dos membros da Dev Team.

Usa a desestruturação no argumento da função para extrair o registo do tipo Ticket, bem como o campo de que precisas. Depois, usa uma única instrução case para verificar se o ticket está atribuído à Alice, ao Bob ou ao Charlie, usando correspondência de padrões recursiva para extrair os respetivos nomes de utilizador e correspondência de padrões literal para os identificar.

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

4. Atribuir tickets a funcionários de TI

Às vezes, vários tickets precisam de ser reatribuídos a outros funcionários de TI.

Define uma função assignTicketTo para te ajudar a fazer isso. A função recebe dois argumentos: um utilizador a quem atribuir o ticket e um ticket. Se o estado do ticket for New, atribui-o ao novo utilizador e muda o estado para InProgress. Para os outros estados, limita-te a reatribuir o ticket aos novos utilizadores, exceto os tickets com o estado Archived, que não devem ser modificados de forma alguma.

Usa a desestruturação no argumento da função para extrair o registo do tipo Ticket, bem como o campo de que precisas, e usa também a palavra-chave as para capturar o registo inteiro tal como está. Usa uma única instrução case para fazer correspondência de padrões sobre o estado e devolver o ticket adequado, criado a partir da modificação do registo original que capturaste com a palavra-chave 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!!" ) ]
--        }
Editar via GitHub A ligação abre numa nova janela ou separador
Elm Exercism

Estás pronto para começar Bilhete, por favor!?

Inscreve-te no Exercism para aprenderes e dominares Elm com 28 conceitos110 exercícios, e mentoria humana real, tudo grátis.