- Elm é um linguagem de programação projetada para construir aplicações front-end.
- Elm é uma linguagem de programação funcional e excelente alternativa ao JavaScript.
- Em JavaScript é difícil de escrever bom código, livre de bugs e manutenível.
- É necessario conhecimento extensivo, muita experiência e disciplina para isso.
- Muitas linguagens foram criadas para tentar melhorar o JavaScript como CoffeeScript, Dart e TypeScript.
- O JavaScript evoluiu bastante adicionando novas funcionalidades, porém não removeu as partes ruins.
- Algumas das principais características e benefícios da linguagem Elm:
- ótima linguagem para escrever aplicações web front-end
- cuidadosamente pensada e criada por Evan Czaplicki
- poderosa e simples de se utilizar
- equilíbrio entre idealismo e pragmatismo
- chance nula de erros em tempo de execução
- é uma linguagem compilada
- fácil depuração
- os efeitos colaterais, comum em navegadores, são controlados
- no JavaScript os erros podem estar em qualquer lugar no código
- fácil de refatorar
- pode ser feita com facilidade e confiança
- no JavaScript, existe muito medo e incertezas
- o compilador ajuda no processo de refatoração
- se compila, funciona
- código com melhor manutenibilidade
- tipagem estática
- o sistema de tipos estáticos não é igual ao Java
- permite corrigir bugs em tempo de desenvolvimento
- é melhor encontrar erros em tempo de desenvolvimento ao invés de produção
- melhor produtividade
- os conceitos da linguagem são simples
- utiliza-se dados imutáveis e funções
- não se utiliza objetos complexos com estados e inúmeros padrões de projetos
- permite atingir o "fluxo"
- melhor testabilidade
- utiliza-se funções puras
- TDD não se faz necessário pois um código Elm já é testável
- força versionamento semântico
- utiliza o Elm Package Manager
- o gerenciador de pacote realiza a verificação
- Elm expõe uma quantidade grande de péssimos hábitos em outras linguagens.
- Elm permite conhecer os benefícios de uma linguagem de programação funcional e usá-las em outras linguagens.
- A melhor forma de aprender programação funcional é através de uma linguagem puramente funcional.
- O Elm disponibiliza um instalador para Windows e Mac.
- O Elm pode ser instalado também através do NPM, que é a opção mais recomendada.
- O Elm pode ser instalado utilizando o comando
npm install -g elm. - O Elm possui um excelente suporte para diversos editores como o Atom e o Sublime Text.
- No Sublime Text, recomenda-se instalar o Elm Language Package através do instalador de pacotes.
- No Atom, recomenda-se instalar o pacote
language-elmpara ter autocomplete e syntax highlight. - A instalação de pacotes no Atom pode ser feita através da linha de comando utilizando o
apm. - O pacote
language-elmpode ser instalado utilizando o comandoapm install language-elm. - No Atom, recomenda-se instalar também o pacote
elm-oracleque adicionar diversas outras funcionalidades em relação ao Elm. - O pacote
elm-oraclepode ser instalado utilizando o comandonpm install -g elm-oracle. - Após sua instalação, deve-se adicionar o caminho do
elm-oraclenas configurações do Atom. Para isso, obtém-se o caminho utilizando o comandowhich elm-oracle. - Recomenda-se instalar também o pacote
elm-formatpara formatação de acordo com os padrões da comunidade. - O
elm-formatpode ser instalado baixando o executável em https://github.com/avh4/elm-format e movendo para o diretório de executáveis utilizando o comandosudo mv elm-format /usr/local/bin/elm-format. - No Atom, recomenda-se instalar o pacote
elm-formatpara formatação de código. - O pacote
elm-formatpode ser instalado utilizando o comandoapm install elm-format. - É uma boa prática selecionar a opção format on save no Atom para realizar a formatação ao salvar o arquivo.
- No Atom, recomenda-se instalar um linter utilizando o comando
apm install linter. - Pode-se instalar um linter para Elm utilizando o comando
apm install linter-elm-make. - Após sua instalação, deve-se adicionar o caminho do
elm-makenas configurações do Atom. Para isso, obtém-se o caminho utilizando o comandowhich elm-make. - Para mais informações sobre as ferramentas, basta acessar https://atom.io/packages/language-elm e https://github.com/ElmCast/elm-oracle.
- A programação funcional é um estilo de programação que utiliza funções puras.
- Uma função pura é uma função que retorna um valor baseado na entrada e sem efeitos colaterais.
- Uma função pura possui as seguintes características:
- deve ter uma entrada de valor
- deve retornar um valor
- não deve utilizar estados
- não deve causar efeito colateral
- Uma função pura possui as seguintes vantagens:
- reusável
- componível
- testável
- cacheável
- paralelizável
- A utilização de funções puras permite que tenhamos mais foco.
- A programação funcional não diz que não se deve ter estado, muito pelo contrário.
- Uma aplicação é composta por estado e pela alteração do estado.
- A programação funcional é sobre eliminar o estado quando possível e controlar o estado quando necessário.
- Um código com estado não controlado deixa o código feio e difícil de manter.
- É possível utilizar o estilo de programação funcional em linguagens não funcionais.
- Essa é uma ótima abordagem e altamente recomendada.
- É possível utilizar programação funcional no JavaScript, mas requer muita disciplina.
- Porém, como a linguagem e o interpretador não se importam com o código, não temos todas as garantias e benefícios da programação funcional.
- Utilizar uma linguagem de programação funcional força a programação funcional.
- Ou seja, somos forçados a utilizar funções puras e dados imutáveis, por exemplo.
- No Elm, para imprimir um texto na tela, deve-se utilizar a função
textdo pacoteHtml. - O Elm possui um excelente gerenciador de pacotes.
- Os diversos pacotes podem ser consultados em http://package.elm-lang.org.
- Para instalar o pacote
Htmlutiliza-se o comandoelm-package install elm-lang/html. - Para utilizar o pacote
Htmlutiliza-se o comandoimport Html. - Ao instalar o pacote
Html, outros pacotes também serão instalados como dependências. - Para imprimir um texto na tela, utiliza-se a função
HTML.text, sem a necessidade de parênteses e separando o argumento com um espaço. Por exemplo,Html.text "Hello World". - Pode-se utilizar a ferramenta Elm Reactor para executar a aplicação.
- O Elm Reactor cria um um servidor web, compila e executa automaticamente a aplicação no navegador.
- Para iniciar o Elm Reactor utiliza-se o comando
elm reactor. - Para executar a aplicação basta acessar o endereço
http://localhost:8000no navegador e clicar no nome do arquivo Elm da aplicação desejada.
- Uma função no Elm é definida pelo seu nome, seguido dos argumentos separados por espaço, um sinal de igual e o corpo da função. Por exemplo,
add a b = a + b. - Não é necessário utilizar
returnpois o corpo da função é uma expressão. - Para chamar a função basta informar o nome da função seguido dos parâmetros separados por espaços. Por exemplo,
add 1 2. - Como o corpo de uma função é uma expressão, uma cláusula
ifdeverá sempre conterelse. - O Elm é fortemente tipado e não faz conversão implícita de tipos.
- A função
toStringé utilizada para converter um valor de qualquer tipo para uma String. - Ela é importada por padrão em todas as aplicações Elm.
- É recomendável utilizar parênteses para sinalizar a ordem da aplicação das funções.
- Por exemplo, em
toString add 1 2estamos passando três argumentos para a funçãotoString. Para realizar a adição e depois a conversão para string deveremos utilizar os parênteses como emtoString (add 1 2). - O operador
|>(forward pipe operator) é utilizado para utilizar o resultado da expressão à esquerda como argumento da expressão à direita. - A aplicação parcial de uma função consiste em chamar uma função fornecendo parte de seus argumentos.
- Uma função anônima é definida por uma barra invertida (
\), seguidos dos argumentos separados por espaço, um sinal->e o corpo da função anônima. Por exemplo,\a -> a % 2 == 0é uma função anônima que verifica se um número é par ou ímpar. - Em Elm não é permitido a utilização de funções impuras.
- É possível utilizar variáveis locais através da cláusula
let .. in. Neste caso, só podemos atribuir um valor e nunca alterá-lo por causa da imutabilidade.
- Em Elm, quase tudo é uma função ou "funciona" como uma função.
- Em Elm, o operador
+é uma função infixa. - É mais comum se utilizar funções prefixas em programação imperativa.
- Uma função infixa, como o operador
+, é posicionada entre os parâmetros e permite uma melhor legibilidade. - Ao criar uma função que não contenha caracteres alfanuméricos, ela será uma função infixa. Por exemplo,
(~+) a b = a + b + 0.1é uma função infixa e é utilizada como emresult = 1 ~+ 2. - Pode-se chamar uma função prefixa como uma função infixa utilizando backticks (
`). Por exemplo,result = 1 `add` 2. - Pode-se chamar uma função infixa como uma função prefixa utilizando parênteses. Por exemplo,
result = (~+) 1 2. - Uma das vantagens de se utilizar funções puras é a composição de funções.
- A composição de função permite criar uma nova função a partir da combinação de uma ou mais funções.
- O operador
>>permite realizar a composição de funções em Elm.
- O Elm possui tipos primitivos como
String,InteBoole também tipos avançados comoRecordseUnion Types. - No Elm, o sistema de tipos estático é razoavelmente diferente do que estamos acostumados.
- Sistemas de tipos estáticos normalmente possuem alguns problemas como:
- declarações longas e verbosas
- compilação lenta
- mensagens de erros de difícil compreensão
- erros em tempo de execução
- O sistema de tipos estático do Elm possui as seguintes características:
- inferência de tipos
- não é necessário declarar explicitamente os tipos
- assemelha-se linguagens dinâmicas
- compilação rápida
- mensagens de erros amigáveis e úteis
- sugestões de correção
- sem erros em tempo de execução
- inferência de tipos
- Um compilador é responsável por transformar o código fonte em linguagem de máquina ou linguagem intermediária.
- No Elm, o processo de compilação permite transformar o código fonte Elm em JavaScript e encontrar e consertar erros em tempo de desenvolvimento.
- O Elm possui tipos primitivos como
String,Char,Bool,Floatenumber. - O tipo
numberé um tipo genérico que pode serIntegerouFloat. - O tipo
Listrepresenta uma lista de valores todos do mesmo tipo. Por exemplo,["Anna", "Bob", "Carol"]é uma lista de strings. - O tipo tupla representa uma lista ordenada de valores não necessariamente do mesmo tipo. Por exemplo,
("pi", 3.14)é uma tupla com uma string e um float. - O tipo
Recordrepresenta uma estrutura de dados semelhante a um objeto no JavaScript. Por exemplo,person = { name = "James", age = 42 }. - Não é possível acessar um campo inexistente em um
Record. - Um campo de um
Recordnão pode serundefinedounulle não pode ser auto-referenciado. - Um
Recordé um grupo de campos relacionados. - Para acessar um campo de um
Recordutiliza-se a notação de ponto como emperson.name, por exemplo. - Ao tentar acessar um campo inexistente em um
Recordum erro de compilação será disparado. - Pode-se acessar como uma função o campo de um
Recordatravés da notação de ponto como em.name person, por exemplo. - Um campo de um
Recordpode ser alterado utilizando a sintaxenewPerson = { person | age = 31 }. - No Elm, as estruturas de dados são imutáveis. Logo, ao alterar o valor de
Recordum novoRecordé gerado. - No Elm, tipos mais complexos podem ser representados através de union types.
- As union types assemelham-se a enumerações de tipos diferentes.
- Pode-se criar union types para tipos diferentes de eventos ou ações em uma aplicação. Por exemplo,
type Action = AddPlayer | Scoreoutype Action = AddPlayer String | Score Int Int. - Os tipos que levam parâmetros adicionais podem ser tratados com funções (sua anotação de tipos é representada como funções).
- Em uma aplicação Elm, costuma-se utilizar uma union type chamada
Msgpor convenção. - A mensagem flui através da aplicação e determinadas ações tratam as mensagens corretamente.
- Pode-se utilizar pattern matching para decodificar as mensagens e responder a cada uma delas.
type Msg = Msg1 Int | Msg2 String
msg = Msg2 "James"
case msg of
Msg1 num -> "The number is " ++ (toString num)
Msg2 name -> "Hello " ++ name- O pattern matching deve cobrir o maior número de situações possíveis.
- A maioria das linguagens sejam estáticas ou dinâmicas permitem que variáveis armazenem um valor ou nulo.
- O
nullé um dos maiores problemas de projetos de linguagens de programação. - O problema é conhecido como "billion-dollar mistake".
- Muito tempo é desperdiçado com exceções ocasionados por valores nulos.
- O Elm não suporta valores nulos.
- Em Elm, utiliza-se o tipo
Maybepara representar uma variável que pode ou não conter um valor. Maybeé um union type que pode conter um valor (ouJust) ou nenhum valor (ouNothing).- Pode-se obter
Nothingao tentar retornar o primeiro elemento de uma lista vazia. Por exemplo,List.head []retornaNothing. - Utilizar
Maybeé como checar por nulos em outras linguagens. - Utilizar
Maybepermite que o compilador garanta a sua utilização correta. - O tipo
Resulté utilizado em uma computação que pode falhar. - Ele deve ser utilizado para o gerenciamento de erros no Elm.
Resulté um union type com duas possibilidades comoMaybe. Uma possibilidade éOk, que contem o valor calculado e a outra possibilidade éErr, que contem informações de erro.- Pode-se utilizar a função
Maybe.withDefaultpara mostrar uma mensagem padrão casoMaybenão contenha nenhuma informação. - As funções são valores e podem ser passadas como argumentos e retornadas como valor.
- Uma função de alta ordem é uma função que recebe outra função como argumento ou retorna como valor.
- A função
Maybe.mapé um exemplo de uma função de alta ordem.
- As anotações de tipos estão presentes nos linters, na documentação e no REPL do Elm.
- As anotações de tipos são utilizadas para informar o tipo de entrada e saída de uma função ou de uma constante.
- A utilização de anotação de tipos é opcional no Elm.
- O compilador pode inferir os tipos.
- É encorajado utilizar anotações de tipos em Elm.
- Algumas vantanges de utilizar anotações de tipos são:
- expressividade - permite conhecer com mais detalhes as entradas e saídas das funções
- restritividade - permite ser mais específico ao definir uma anotação de tipo
- escrever melhores funções - permite escrever funções mais gerais e usáveis
- É difícil pensar em tipos e pensar de maneira abstrata e isso vem com experiência.
- Para definir uma anotação de tipo para uma função utilize o nome da função, seguido de dois-pontos, seguido dos tipos dos argumentos e do tipo de retorno separados por
->. Por exemplo,add : Int -> Int -> Int. - O tipo
comparablerepresenta qualquer tipo que pode ser comparado como strings, caracteres e números. - Pode-se definir uma anotação de tipos para uma lista de registros como em
cart : List { name : String, ... }. - Pode-se definir um type alias como em
type alias Item = { name : String, ... }. - A utilização de type aliases permite torna o código mais compreensível.
- A anotação de tipos da função
mainémain : Html.Html msg.
- Uma aplicação Elm possui três partes: model, update e view.
- A model é como um contêiner que armazena os dados que a aplicação necessita.
- A model pode ser um tipo primitivo como um
IntouStringou um tipo complexo como umRecord. Por exemplo,type alias Model = Int. - A seção update é responsável por atualizar a model ou estado da aplicação.
- Na seção update definimos (1) o que pode acontecer na aplicação e (2) como a model é atualizada.
- Definimos o que pode acontecer na aplicação utilizando union types como em
type Msg = AddCalorie | Clear. - Definimos como a model é atualizada utilizando um função
updateque recebe uma mensagem e a model como argumentos e retorna uma nova model. Por exemplo,update : Msg -> Model -> Model. - A view é responsável por criar o HTML levando em consideração a model atual ou o estado da aplicação.
- A view é criada de maneira declarativa.
- A view normalmente é uma função
viewque recebe a model como argumento e retorna o HTML. Por exemplo,view : Model -> Html Msg. - No módulo Html do Elm, existem diversas funções responsáveis pela criação das tags HTML.
- As funções responsáveis pela criação das tags HTML possuem assinaturas consistentes.
- O nome da função é o nome da tag HTML, o primeiro argumento é uma lista de atributos e o segundo argumento é uma lista de elementos filhos. Por exemplo,
div [] []retornará<div></div>oup [class "story"] [text "once"]retornará<p class="story">once</p>. - É possível utilizar uma função de um módulo sem a necessidade de informá-lo explicitamente como em
Html.text "Hello World". - Isso pode ser feito importando o módulo em questão e expondo as funções desejadas. Por exemplo,
import Html exposing (div, p, button, text). - Pode-se importar todas as funções utilizando a notação
... Por exemplo,import Html exposing (..). - Para se utilizar atributos HTML deve-se importar os módulos
Html.AttributeseHtml.Events. Por exemplo,import Html.Attributes exposing (..). - Ao utilizar o atributo
type, deve-se adicionar uma aspa simples após seu nome para diferenciá-lo da palavra-chave reservadatypede Elm. Por exemplo,button [type' "button"]. - Em
view : Model -> Html Msgdiz que a funçãoviewrecebe umaModelcomo argumento e retorna umHtmlcomo resultado que pode gerar umaMsg. - A função
beginnerProgramdo móduloHtmlé responsável por juntar as três partes (model, view e update) de uma aplicação Elm, ou seja, manter o estado da aplicação, gerenciar as mensagens e chamar as funçõesvieweupdatede acordo com a necessidade. - O funcionamento do fluxo da aplicação em Elm é a seguinte:
- a model inicial define o estado atual da aplicação
- a função
viewé chamada com o estado atual da aplicação ou model - a função
viewgera uma representação visual do estado atual da aplicação - uma mensagem é gerada e a função
updateé chamada com a mensagem e o estado atual da aplicação como argumentos - a função
updatecria uma nova model baseada na mensagem informada e na model anterior - a nova model é retornada e armazenada como o novo estado atual da aplicação
- a função
viewé chamada novamente com o estado da aplicação atualizado - e a função
viewgera uma nova representação visual do novo estado atual da aplicação
- O estado da aplicação é gerenciado pelo módulo
Htmle trabalha exclusivamente com funções puras.
- O tipo
Maybe Stringdiz que um valor pode ou não ser uma string. - O type alias pode ser utilizado como uma função para construir novos valores.
- Ao tentar converter um valor de string para inteiro utilizando a função
String.toInt, pode-se obterOkouErr.
- Recomenda-se planejar uma aplicação Elm pensando em model, update e view.
- Recomenda-se quebrar a aplicação em componentes ou funções.
- Utiliza-se o comando
elm makepara compilar código Elm. - Em
elm make ./Main.elm --output ./bundle.js, a aplicação Elm é compilada para um arquivo chamadobundle.js. - O arquivo gerado a partir da compilação pode ser incluído normalmente em um arquivo HTML.
- Deve-se lembrar de associar a aplicação Elm a um elemento do HTML. Por exemplo,
var app = Elm.Main.embed(document.getElementById("app")). - Pode-se utilizar uma ferramenta como o Gulp para automatizar a compilação de uma aplicação Elm.
- A utilização de pattern matching deve ser exaustiva e cobrir todos os casos possíveis.
- Pode-se utilizar o
_como coringa em pattern matching postergar a implementação de todos os casos possíveis. - O Elm utiliza uma implementação de virtual DOM poderosíssima.
- Pode-se utilizar a função
Debug.logpara imprimir informações no log do navegador.
- Para adicionar um valor em uma lista utiliza-se o operador
++. Por exemplo,newPlayers = players ++ [player]. - O operador
++opera somente sobre listas. Por isso, devemos colocar o valor dentro de uma lista antes de concatenar. - Pode-se utilizar o operador
::(cons) para adicionar um valor no começo de uma lista. - Utilizar o operador
::é mais performático pois, para adicionar o valor no início da lista, não é preciso percorrer a lista inteira. - Pode-se utilizar a função
List.mappara aplicar uma função em cada elemento de uma lista.
- Recomenda-se utilizar a função
List.sortBypara ordenar uma lista de acordo com um campo. Por exemplo,List.sortBy .name users.
- Recomenda-se utilizar a função
List.filterpara filtrar uma lista de acordo com uma condição. Por exemplo,List.filter (\u -> u.age >= 18) users. - A utilização do caractere coringa
_não se faz necessária quando se cobre todos os casos em pattern matching.
- Recomenda-se conhecer como se trabalha com HTTP, web sockets, componentes, single page apps, comunicação com o JavaScript, testes entre outras coisas em Elm.