MATA56 - Paradigmas de Linguagens de Programação
16/05/2016
Alesson Bruno, Cristiano Santos e Felipe Rabello
- DIFERENTES CONSTRUTORES
- EXCELENTE FERRAMENTAL
- METAPROGRAMAÇÃO
- POLIMORFISMO (PROTOCOLS)
- MACROS
- E MAIS ...
Direitos reservados da Plataformatec
Código fonte: Apache 2 License
ZILHÕES DE TRANSISTORES
MUITOS NÚCLEOS
COMO MANTÊ-LOS OCUPADOS?
EXPLORANDO TRABALHO
FUNCIONAL E CONCORRENTE
FUNCIONAL NÃO PRECISA SER MATEMÁTICO
NEM COMPLEXO
FUNCIONAL E CONCORRENTE
CONCORRENTE SEM ABSTRAÇÕES COMO:
LOCKS E SEMÁFOROS
MULTI PARADIGMA
FUNCIONAL, CONCORRENTE, DISTRIBUÍDO E
ORIENTADO A PROCESSOS
COMPILADA PARA O BYTECODE DA MÁQUINA DO ERLANG (BEAM)
ERLANG POSSUI GARBAGE COLLECTOR (GC)
ELIXIR RODA EM CIMA DA MÁQUINA DO ERLANG
ELIXIR TAMBÉM POSSUI GC
MILHARES DE PROCESSOS CONCORRENTES
PROCESSOS ISOLADOS COM GC INDEPENDENTE
REDUZ PAUSAS
UTILIZA MAIS RECURSOS DA MÁQUINA EFICIENTEMENTE
CASE, COND E IF
CASE
case {1, 2, 3} do
{4, 5, 6} ->
"This clause won't match"
{1, x, 3} ->
"This clause will match and bind x to 2 in this clause"
_ ->
"This clause would match any value"
end
# output
"This clause will match and bind x to 2 in this clause"COND
cond do
2 + 2 == 5 ->
"This will not be true"
2 * 2 == 3 ->
"Nor this"
1 + 1 == 2 ->
"But this will"
end
# output
"But this will"IF E UNLESS
if true do
"This works!"
end
# output
"This works!"
unless true do
"This will never be seen"
endLOOPS EM ELIXIR (ASSIM COMO EM OUTRA LINGUAGEM FUNCIONAL) SÃO ESCRITOS DE FORMA DIFERENTE DAS LINGUAGENS IMPERATIVAS
USAR RECURSÃO, REDUCE, MAP, ...
RECURSÃO
defmodule Recursion do
def print_multiple_times(msg, n) when n <= 1 do
IO.puts msg
end
def print_multiple_times(msg, n) do
IO.puts msg
print_multiple_times(msg, n - 1)
end
end
Recursion.print_multiple_times("Hello!", 3)
# Hello!
# Hello!
# Hello!O PODER DA RECURSÃO
defmodule Math do
def sum_list([head | tail], accumulator) do
sum_list(tail, head + accumulator)
end
def sum_list([], accumulator) do
accumulator
end
end
IO.puts Math.sum_list([1, 2, 3], 0) #=> 6REDUCE E MAP
Enum.reduce([1, 2, 3], 0, fn(x, acc) -> x + acc end)
# output
6
Enum.map([1, 2, 3], fn(x) -> x * 2 end)
# output
[2, 4, 6]AS VARIÁVEIS EM ELIXIR DEVEM COMEÇAR COM LETRA MINÚSCULA OU UM UNDERSCORE (_), TEREM UM OU MAIS CARACTERES, SENDO ELES LETRAS, NÚMEROS OU UNDERSCORE (_). NÃO PODEM SER KEYWORDS
AS VARIÁVEIS EM ELIXIR SÃO CASE SENSITIVE. LOGO, someVar, somevar E SOMEVAR SÃO VARIÁVEIS DIFERENTES
ELIXIR É UMA LINGUAGEM DINAMICAMENTE TIPADA, LOGO, NÃO PRECISAMOS DEFINIR O TIPO DAS VÁRIAVEIS QUANDO INICIADAS, SEU TIPO É ATRIBUÍDO EM TEMPO DE EXECUÇÃO. ELA TAMBÉM É FORTEMENTE TIPADA.
MATCH OPERATOR
# Assign value
x = 1
IO.puts x # 1
# Match operator
1 = x
# 1
2 = x
** (MatchError) no match of right hand side value: 1MATCH OPERATOR
{a, b, c} = {:hello, "world", 42}
# {:hello, "world", 42}
[a, b, c] = [1, 2, 3]
# [1, 2, 3]
[head | tail] = [1, 2, 3]
# [1, 2, 3]
head
# 1
tail
# [2, 3]OS TIPOS DE DADOS EM ELIXIR SÃO IMUTÁVEIS. ISSO SIGNIFICA QUE, MODIFICANDO UMA VARIÁVEL, O ELIXIR RETORNA UMA NOVA ESTRUTURA. SENDO IMUTÁVEL, VOCÊ NÃO PRECISA SE PREOCUPAR QUE UM BLOCO DE CÓDIGO PARTICULAR ESTÁ MUTANDO SUA ESTRUTURA DE DADOS EM ALGUM LUGAR.
O ELIXIR NÃO SUPORTA FUNÇÕES ANINHADAS. PELAS SUAS REGRAS DE ESCOPO, PODEMOS ANINHAR MÓDULOS, E PARA CADA MÓDULO ANINHADO, DEFINIR FUNÇÕES.
defmodule P do
defmodule Q do
def q(false), do: "sorry"
def q(true) do
defmodule M do
def say, do: "hi"
end
end
end
end
P.Q.q false #=> "sorry"
# the module hasn't been defined yet
P.Q.M.say #=> undefined function: P.Q.M.say/0
# after this call the P.Q.M module will become available
P.Q.q true
P.Q.M.say #=> "hi"EM ELIXIR, AS FUNÇÕES ANÔNIMAS SÃO AS FUNÇÕES COMO CIDADÃOS DE PRIMEIRA CLASSE
defmodule Math do
def square(x) do
x * x
end
end
Enum.map [1, 2, 3], &Math.square/1
#=> [1, 4, 9]closures = []
i = 0
closures = closures ++ [fn -> IO.puts i end]
i = 1
closures = closures ++ [fn -> IO.puts i end]
i = 2
closures = closures ++ [fn -> IO.puts i end]
Enum.at(closures, 0).()
Enum.at(closures, 1).()
Enum.at(closures, 2).()
# 0
# 1
# 2MIX
$ mix new example
* creating README.md
* creating .gitignore
* creating mix.exs
* creating config
* creating config/config.exs
* creating lib
* creating lib/example.ex
* creating test
* creating test/test_helper.exs
* creating test/example_test.exsdefmodule Example.Mixfile do
use Mix.Project
def project do
[app: :example,
version: "0.0.1",
elixir: "~> 1.0",
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
deps: deps]
end
def application do
[applications: [:logger]]
end
defp deps do
[]
end
enddef deps do
[{:phoenix, "~> 0.16"},
{:phoenix_html, "~> 2.1"},
{:cowboy, "~> 1.0", only: [:dev, :test]},
{:slim_fast, ">= 0.6.0"}]
end$ mix deps.getEM ELIXIR, TODO O CÓDIGO RODA EM PROCESSOS. PROCESSOS SÃO ISOLADOS UM DOS OUTROS, SÃO CONCORRENTES E SE COMUNICAM POR MENSAGENS.
OS PROCESSOS DO ELIXIR NÃO DEVEM SER CONFUNDIDOS COM OS PROCESSOS DO SISTEMA OPERACIONAL. ELES SÃO BEM LEVES EM TERMOS DE MEMÓRIA E CPU. POR CAUSA DISSO, NÃO É INCOMUM TER DEZENAS OU ATÉ CENTENAS DE MILHARES DE PROCESSOS RODANDO SIMULTANEAMENTE
parent = self()
#PID<0.41.0>
spawn fn -> send(parent, {:hello, self()}) end
#PID<0.48.0>
receive do
{:hello, pid} -> "Got hello from #{inspect pid}"
end
# output
"Got hello from #PID<0.48.0>"