Skip to content

Latest commit

 

History

History
482 lines (333 loc) · 14.5 KB

chapter3.livemd

File metadata and controls

482 lines (333 loc) · 14.5 KB

Learn4Elixir - Capítulo 3

Estruturas de Controle

Neste capitulo iremos nos aprofundar em Estruturas de Controle.

Run in Livebook

If e Unless

'if' e 'unless' são estruturas de controle que você pode usar no Elixir. Eles funcionam de maneira semelhante ao condicional 'if' e 'unless' em outras linguagens de programação. Aqui está como você pode usá-los:

If

A estrutura 'if' é usada para executar um bloco de código se uma condição for avaliada como verdadeira ou algum valor 'truthy'. Se a condição for avaliada como falsa ou algum valor 'falsy', o bloco de código não será executado.

if condition do
  # Código a ser executado se a condição for verdadeira
end

Exemplo:

age = 25

if age >= 18 do
  "Você é maior de idade."
end
age = 25

if age do
  "Você é maior de idade."
end
condicao = false

if condicao do
  "Você é maior de idade."
end
condicao = nil

if condicao do
  "Você é maior de idade."
end

Observe que, se a condição for 'false' ou 'nil', o comando retorna 'nil', na ausência de uma cláusula 'else' (que veremos depois).

Unless

A estrutura 'unless' é mais ou menos o oposto do if. Ela é usada para executar um bloco de código se a condição for avaliada como falsa ou 'falsy'. Se a condição for avaliada como verdadeira ou 'truthy', 'nil' será retornado.

unless condition do
  # Código a ser executado se a condição for falsa
end

Exemplo:

raining = false

unless raining do
  "Não está chovendo."
end
raining = nil

unless raining do
  "Não está chovendo."
end
raining = true

unless raining do
  "Não está chovendo."
end
raining = :oi

unless raining do
  "Não está chovendo."
end

Você também pode usar 'else' com 'if' e 'unless' para executar um bloco de código alternativo quando a condição não for atendida.

if condition do
  # Código a ser executado se a condição for verdadeira
else
  # Código a ser executado se a condição for falsa
end

Exemplo:

temperature = 28

if temperature > 30 do
  "Está quente lá fora."
else
  "Não está tão quente lá fora."
end
temperature = 35

if temperature > 30 do
  "Está quente lá fora."
else
  "Não está tão quente lá fora."
end

A mesma lógica se aplica ao 'unless' com 'else'.

temperature = 28

unless temperature > 30 do
  "Está quente lá fora."
else
  "Não está tão quente lá fora."
end
temperature = 35

unless temperature > 30 do
  "Está quente lá fora."
else
  "Não está tão quente lá fora."
end

Cond

No Elixir, você pode usar a macro 'cond' para criar uma estrutura de controle condicional que permite avaliar múltiplas condições e executar código com base na primeira condição verdadeira encontrada. A sintaxe básica do cond é a seguinte:

cond do
  condition1 ->
    # Código a ser executado se condition1 for verdadeira

  condition2 ->
    # Código a ser executado se condition2 for verdadeira

  condition3 ->
    # Código a ser executado se condition3 for verdadeira

  true ->
    # Código a ser executado se nenhuma das condições anteriores for verdadeira
end

Aqui estão alguns pontos-chave a serem observados sobre o cond no Livebook:

O cond avaliará as condições na ordem em que são declaradas e executará o código associado à primeira condição verdadeira encontrada. Se nenhuma das condições for verdadeira, o bloco de código associado a true será executado, se presente.

As condições são seguidas por uma seta (->) e, em seguida, o código a ser executado se a condição for verdadeira.

A última cláusula com true é opcional, mas é uma boa prática incluí-la para tratar casos em que nenhuma das condições anteriores é verdadeira.

Aqui está um exemplo de uso do cond no Livebook:

x = 5

cond do
  is_number(x) and x == 0 ->
    "x é igual a 0"

  is_number(x) and x > 0 ->
    "x é maior que 0"

  is_number(x) and x < 0 ->
    "x é menor que 0"

  true ->
    "Nenhuma das condições anteriores foi atendida"
end

Neste exemplo, o código verificará a condição x == 0 primeiro, que não é verdadeira, e, em seguida, verificará x > 0, que é verdadeira, portanto, imprimirá "x é maior que 0". Como a última cláusula com true está presente, ela não será executada neste caso.

Mude o valor de 'x' no código acima para 0 e -1 e reavalie, para ver o que acontece. Depois, mude 'x' para o átomo ':a' e reavalie.

Sigils

Elixir fornece uma sintaxe alternativa para representar e trabalhar com literais. Um sigil (símbolo especial) vai começar com um til ~ seguido por um caractere. O núcleo do Elixir fornece-nos alguns sigils, no entanto, é possível criar o nosso próprio sigil quando precisamos estender a linguagem.

Uma lista de sigils disponíveis incluem:

  • ~C Gera uma lista de caracteres sem escape ou interpolação
  • ~c Gera uma lista de caracteres com escape e interpolação
  • ~R Gera uma expressão regular sem escape ou interpolação
  • ~r Gera uma expressão regular com escape e interpolação
  • ~S Gera strings sem escape ou interpolação
  • ~s Gera string com escape e interpolação
  • ~W Gera uma lista sem escape ou interpolação
  • ~w Gera uma lista com escape e interpolação
  • ~N Gera uma NaiveDateTime struct

Uma lista de delimitadores inclui:

  • <...> Um par de brackets
  • {...} Um par de chaves
  • [...] Um par de colchetes
  • (...) Um par de parênteses
  • |...| Um par de pipes
  • /.../ Um par de barras
  • "..." Um par de aspas duplas
  • '...' Um par de aspas simples

Aqui estão alguns exemplos de como usar sigils no Livebook:

Sigil de String (~s)

Você pode usar o sigil ~s para criar strings. O texto deve ser colocado entre colchetes {}. Por exemplo:

~s{Isso é uma string criada com sigil}

Isso retornará "Isso é uma string criada com sigil" na saída.

Sigil de Regex (~r)

O sigil ~r permite criar expressões regulares. Você pode delimitar a expressão regular com barras /. Por exemplo:

# Esta expressão regular corresponde a um ou mais dígitos.
regex = ~r/\d+/
texto = "123 ABC  45 CDE"
Regex.scan(regex, texto)

Isso irá retornar uma lista de resultados. Cada resultado será uma lista contendo uma string que satisfaz à expressão regular, que espera caraceteres numéricos.

Sigil de Caracter (~c)

O sigil ~c permite criar caracteres. Você pode especificar um único caractere entre aspas simples '. Por exemplo:

~c'A'

Isso retornará "A".

Sigil de Listas (~w):

O sigil ~w permite criar listas de palavra (strings) a partir de átomos, expressos sem os ":" iniciais. Você pode delimitar as palavras com espaços. Por exemplo:

~w(apple banana cherry)

Compreensões

No Elixir, você pode usar compreensões para criar listas ou outras estruturas de dados de maneira concisa e expressiva. Compreensões são uma característica poderosa em Elixir e podem ajudar a simplificar a criação e transformação de coleções de dados. Aqui estão algumas formas de usar compreensões:

Compreensões de Lista

Você pode criar listas usando compreensões de lista. A estrutura básica de uma compreensão de lista é a seguinte:

for pattern <- enumerable, filter, do: expression
  • 'pattern' é uma variável que representa cada elemento da coleção 'enumerable'.
  • 'enumerable' é uma coleção de dados, como uma lista, um mapa ou um conjunto.
  • 'filter' (opcional) é uma condição que filtra os elementos da coleção.
  • 'expression' é o valor que será incluído na lista resultante.

Exemplos:

lista = [1, 2, 3, 4, 5]
for x <- lista, do: x * x
lista = [1, 2, 3, 4, 5]
for x <- lista, x < 4, do: x * x
lista = [10, 2, 30, 4, 50]
for x <- lista, x > 3, x < 40, do: "#{x + 3}"

Compreensões de Mapa

Você também pode usar compreensões para criar mapas. A estrutura básica de uma compreensão de mapa é semelhante à compreensão de lista:

for {key, value} <- enumerable, filter, do: {key, expression}

Exemplo:

mapa = %{"a" => 1, "b" => 2, "c" => 3}
triplica_valores = for {chave, valor} <- mapa, do: {chave, valor * 3}

Compreensões Aninhadas

Você pode aninhar compreensões dentro de outras compreensões para trabalhar com coleções mais complexas. Por exemplo, você pode criar uma lista de listas usando uma compreensão aninhada.

Exemplo:

matriz = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
elementos_pares = for linha <- matriz, valor <- linha, rem(valor, 2) == 0, do: valor

Guard Clauses

Você pode usar guard clauses nas compreensões para aplicar condições adicionais aos elementos.

Exemplo:

lista = [1, 2, 3, 4, 5, 6]
pares_maiores_que_tres = for x <- lista, rem(x, 2) == 0, x > 3, do: x

Exercícios

Exercício 1

Você é um desenvolvedor Elixir que trabalha para uma empresa de jogos chamada "ElixGames". A empresa está criando um jogo de aventura em que os jogadores exploram um mundo mágico cheio de criaturas misteriosas. Como parte do jogo, você precisa implementar uma função que determina o resultado de um encontro aleatório com uma criatura.

Aqui estão as regras para determinar o resultado do encontro:

  • Se o jogador estiver em um "Bosque Encantado", ele tem 90% de chance de encontrar uma criatura amigável e 10% de chance de encontrar uma criatura hostil.
  • Se o jogador estiver em uma "Caverna Escura", ele tem 60% de chance de encontrar uma criatura amigável e 40% de chance de encontrar uma criatura hostil.
  • Se o jogador estiver em uma "Torre Misteriosa", ele tem 30% de chance de encontrar uma criatura amigável e 70% de chance de encontrar uma criatura hostil.

Sua tarefa é implementar um módulo em Elixir chamado ElixGames.Encontro que forneça a função determina_encontro/2, que aceita o local onde o jogador está e um número aleatório entre 1 e 100 (representando a probabilidade) como argumentos e retorna o resultado do encontro com a criatura com base nas regras acima.

Para completar esta tarefa, você precisará usar estruturas condicionais, como if, unless e cond, para aplicar as regras corretamente e determinar se o jogador encontrará uma criatura amigável ou hostil com base no local e na probabilidade gerada aleatoriamente. Certifique-se de que a API (o nome do módulo, da função e suas assinaturas) seja respeitada, conforme especificado pela empresa "ElixGames".

defmodule ElixGames.Encontro do
  def determina_encontro(localizacao, probabilidade) do
    # Implemente a lógica de determinação do resultado do encontro aqui
  end
end

Exercício 2

Você recebeu uma lista de informações de clientes em formato de string, mas elas estão desorganizadas e precisam ser formatadas corretamente. Cada informação de cliente é separada por um ponto e vírgula (;) e contém os seguintes campos:

  1. Nome do cliente (entre aspas duplas).
  2. Idade do cliente (um número).
  3. Endereço de e-mail do cliente.
  4. Número de telefone do cliente.

A seguir está um exemplo de como as informações dos clientes estão atualmente:

"Fulano Tal",30,fulano@email.com,+5511995236587;"Ciclano Outro",25,ciclano@email.com,5545996578452

Dê uma olhada como sigils funcionam. Principalmente ~s e ~r, leia também sobre expressões regulares.

Tarefas:

  1. Crie uma função chamada parsear_clientes/1 que receba a string de informações de clientes e a divida em uma lista de informações de clientes formatadas. Use o sigil ~s para fazer isso.
def parsear_clientes(informacao) do
  # A fazer
end
  1. Crie outra função chamada extrair_nomes/1 que receba a lista de informações de clientes e retorne uma lista com os nomes dos clientes.
def extrair_nomes(clientes) do
  # A fazer
end
# Caso a entrada fosse o exemplo na descrição deve imprimir ["Fulano Tal", "Ciclano Outro"]
  1. Crie uma terceira função chamada filtrar_clientes_por_idade/2 que receba a lista de informações de clientes e uma idade mínima e retorne uma lista com as informações dos clientes que têm pelo menos a idade especificada.
def filtrar_clientes_por_idade(clientes, idade_minima) do
  # A fazer
end
# Deveria imprimir [["Fulano Tal", 30, "fulano@email.com", "+5511995236587"]]

Exercicio 3

Você está trabalhando em uma empresa de e-commerce que vende produtos para pets. Você recebeu a tarefa de implementar uma função que calcula o valor total de uma compra, aplicando possíveis descontos de acordo com as regras de negócio. As regras são as seguintes:

  • Se a compra for acima de R$ 200,00, o cliente ganha 10% de desconto.
  • Se a compra for acima de R$ 500,00, o cliente ganha 15% de desconto.
  • Se a compra for acima de R$ 1000,00, o cliente ganha 20% de desconto.
  • Se o cliente for um membro do clube de fidelidade, ele ganha mais 5% de desconto em qualquer compra.
  • Se o cliente usar o cupom "UBL10", ele ganha mais 10% de desconto em qualquer compra.

Você deve implementar uma função chamada calcula_total que recebe uma lista de produtos e um mapa com as informações do cliente (se ele é membro do clube, se ele usou o cupom, etc) e retorna o valor total da compra com os descontos aplicados. Você pode usar funções de alta ordem para criar funções auxiliares que representam as regras de desconto e aplicá-las na lista de produtos. Cada produto é representado por um mapa com os campos :nome, :preco e :quantidade. Por exemplo:

produtos = [
  %{nome: "Ração para gatos", preco: 50.00, quantidade: 2},
  %{nome: "Brinquedo para cachorro", preco: 30.00, quantidade: 1},
  %{nome: "Aquário", preco: 200.00, quantidade: 1}
]

cliente = %{
  membro_clube: true,
  cupom: "UBL10"
}

calcula_total(produtos, cliente) # deve retornar 243.00
defmodule Ecommerce do
  # A fazer
end