Percursos
/
Julia
Julia
/
Exercícios
/
Namorada do Secundário
Namorada do Secundário

Namorada do Secundário

Exercício de aprendizagem

Introdução

A Julia incentiva os programadores a colocar o máximo de código possível dentro de funções que possam ser compiladas JIT, e criar muitas funções pequenas é, por conceção, eficiente.

Isso tende a deixar muitas funções pequenas e simples, que é preciso combinar para realizar tarefas não triviais.

Uma abordagem óbvia é aninhar chamadas de funções. O exemplo seguinte é muito forçado, mas ilustra a ideia.

julia> first.(titlecase.(reverse.(["my", "test", "strings"])))
3-element Vector{Char}:
 'Y': ASCII/Unicode U+0059 (category Lu: Letter, uppercase)
 'T': ASCII/Unicode U+0054 (category Lu: Letter, uppercase)
 'S': ASCII/Unicode U+0053 (category Lu: Letter, uppercase)

A desvantagem desta abordagem é que a legibilidade cai rapidamente à medida que o aninhamento se aprofunda.

Precisamos de uma abordagem mais simples e mais flexível.

Composição

Esta é a técnica preferida dos matemáticos, e a Julia copia a sintaxe matemática.

Um número arbitrário de funções pode ser composed com operadores ∘ (introduzido como \circ seguido de tab). O resultado pode ser usado como uma única função.

julia> compfunc = first ∘ titlecase ∘ reverse
first ∘ titlecase ∘ reverse
julia> compfunc.(["my", "test", "strings"])
3-element Vector{Char}:
 'Y': ASCII/Unicode U+0059 (category Lu: Letter, uppercase)
 'T': ASCII/Unicode U+0054 (category Lu: Letter, uppercase)
 'S': ASCII/Unicode U+0053 (category Lu: Letter, uppercase)
# alternative syntax, giving the same result
julia> (first ∘ titlecase ∘ reverse).(["my", "test", "strings"])

Alguns pontos a ter em conta:

  • As funções iniciais aparecem na mesma ordem que no aninhamento e são executadas da direita para a esquerda.
  • O broadcasting não é simples de usar na composição, mas pode ser aplicado ao chamar a função composta.

Pipelines

Uma alternativa pode ser encarada como a abordagem dos programadores, em vez da dos matemáticos.

Os Pipelines são usados há muito tempo em scripts de shell do Unix e, mais recentemente, tornaram-se populares em linguagens de programação mais convencionais (por vezes, atribui-se ao F# o pioneirismo na sua adoção).

O conceito básico é começar com alguns dados e depois encadeá-los através de uma sequência de funções para obter o resultado.

O operador de pipe é |> (como no F# e em versões recentes do R), embora a Julia também tenha uma versão broadcast, .|>.

julia> ["my", "test", "strings"] .|> reverse .|> titlecase .|> first
3-element Vector{Char}:
 'Y': ASCII/Unicode U+0059 (category Lu: Letter, uppercase)
 'T': ASCII/Unicode U+0054 (category Lu: Letter, uppercase)
 'S': ASCII/Unicode U+0053 (category Lu: Letter, uppercase)

A execução passa agora a ser estritamente da esquerda para a direita, com o resultado de cada função a fluir no sentido da seta para se tornar no valor de entrada da função seguinte.

Limitações, soluções alternativas e outras opções

Não é por acaso que as funções usadas para ilustrar a composição e os pipelines recebem todas um único argumento.

Algumas linguagens puramente funcionais encaminham o primeiro argumento para uma função, mas permitem incluir outros.

Em contrapartida, a Julia só espera nomes de funções (ou algo equivalente) num pipeline, sem quaisquer argumentos adicionais.

Há razões técnicas importantes para isto (relacionadas com o facto de o currying não ser uma parte padrão do desenho da linguagem). As muitas pessoas que não compreendem o currying devem apenas aceitar que esta limitação não é um descuido, nem é provável que mude em versões futuras da Julia.

Soluções alternativas

Precisamos de funções com um único argumento que façam o que for necessário. Felizmente, definir novas funções na Julia é fácil.

O mais simples é usar uma anonymous function. Por exemplo, se tivermos uma única string de entrada e quisermos dividir pelos underscores:

julia> "my_test_strings" |> (s -> split(s, '_'))
3-element Vector{SubString{String}}:
 "my"
 "test"
 "strings"

Esse vetor poderia depois ser encaminhado para outras funções, como antes.

Neste caso, envolver a função anónima entre parênteses é opcional, mas, de um modo geral, é uma forma útil de reduzir ambiguidades.

Da mesma forma, poderíamos criar uma função com nome, mais cedo no programa, e reutilizá-la conforme necessário.

Instruções

Neste exercício, vais ajudar namorados do secundário a declarar o seu amor nas redes sociais, gerando um coração unicode com as iniciais deles:

❤ J.  +  M. ❤

1. Limpa o nome

Implementa o método cleanupname. Deve receber um nome, remover todos os carateres - e substituí-los por um espaço. Deve também remover os espaços em branco no início e no fim do nome.

julia> cleanupname("Jane-Ann")
"Jane Ann"

2. Obtém a primeira letra do nome

Implementa o método firstletter. Deve receber um nome e devolver a primeira letra desse nome como string. Certifica-te de que reutilizas o cleanupname que definiste no passo anterior, combinando-o com outras funções.

julia> firstletter("Jane")
"J"

3. Formata a primeira letra como uma inicial

Implementa o método initial. Deve receber um nome e devolver a sua primeira letra, em maiúscula, seguida de um ponto. Certifica-te de que reutilizas o firstletter que definiste no passo anterior.

initial("Robert")
"R."

4. Coloca as iniciais dentro do coração

Implementa o método couple. Deve receber dois nomes e devolver as iniciais com corações emoji à volta. Certifica-te de que reutilizas o initial que definiste no passo anterior.

couple("Blake Miller", "Riley Lewis")
"❤ B.  +  R. ❤"
Editar via GitHub A ligação abre numa nova janela ou separador
Julia Exercism

Estás pronto para começar Namorada do Secundário?

Inscreve-te no Exercism para aprenderes e dominares Julia com 35 conceitos128 exercícios, e mentoria humana real, tudo grátis.