Estou apaixonado pela família ML de linguagens de programação por algum tempo. No entanto, e além da Kata ocasional, nunca entreguei nada usando uma linguagem ML.
Dada a recente atividade na comunidade de Ocaml, no entanto – principalmente devido aos esforços de comunicação por trás do Reason do Facebook – me senti compelido a tentar novamente (depois de uma incursão muito curta durante o meu curso de graduação).
Começando e material de leitura
Passei pela configuração inicial do Reason na mesma época em que Jared Forsyth publicou um tutorial muito detalhado sobre como começar com ReasonReact e compilar Reason para o navegador usando BuckleScript.
Apesar de sua pouca idade, o BuckleScript é uma incrível tecnologia que irá (instantaneamente, se eu puder adicionar) compilar o código Ocaml (com built-in) de suporte para Reason, para JavaScript. O manual do BuckleScript, embora um pouco conciso no início, é uma referência fantástica ao trabalho com o compilador e tornou-se uma aba fixa no meu navegador logo que comecei esta jornada.
Próximas etapas e solução de problemas
Mas depois da configuração inicial, eu estava sozinho, e tive que começar em algum lugar. reason-scripts, um template personalizado para create-react-app, acabou sendo uma ótima maneira de desenvolver meu projeto sem o incômodo de escrever código bloilerplate, configurar ferramentas e gastar horas averiguando os erros mais ínfimos.
Como qualquer iniciante que atravessava os obstáculos de paradigmas desconhecidos, não demorou até eu encontrar algumas dificuldades. O que se segue é uma tentativa de documentar as armadilhas que me atrapalharam no início, o que espero seja útil para outros tentando descobrir erros de iniciantes à medida que começam com Reason (React).
A variável do tipo terrível não pode ser generalizada
Em seu tutorial, Jared descreve como fazer um componente stateful, mas quando tentei migrar o meu componente sem estado para um stateful, fui imediatamente saudado pela seguinte mensagem de erro, um pouco enigmática:
Module build failed: Error: File "/path/to/src/app.re", line 5, characters 16-51: Error: The type of this expression, ('_a, ReasonReact.stateless, ReasonReact.noRetainedProps, ReasonReact.noRetainedProps) ReasonReact.componentSpec, contains type variables that cannot be generalized
A solução era simplesmente usar o estado em algum lugar em qualquer função do meu componente. Mesmo apenas desestruturando o estado do e.g. – um simples argumento para render resolve o problema.
Agora, a razão pela qual isso acontece é bastante interessante: se você olhar para o tipo de ReasonReact.statefulComponent, existe um estado de variável de tipo. Essa é a variável a que o erro está se referindo: quando o estado não é usado dentro da definição do componente, o compilador não pode inferir o que queremos que seu tipo seja. Se usado explicitamente, então estamos literalmente dizendo o que essa variável de tipo deve ser.
Uma consideração interessante aqui é que ReasonReact.statelessComponent não possui esse problema. Se olharmos para a definição de tipo, é quase imediatamente óbvio por quê: não há variáveis de tipo à vista. O compilador sempre sabe que ele levará um argumento sem estado (que é definido acima no arquivo como sendo o tipo de unidade).
A equipe por trás do ReasonReact está bem ciente desse erro e de alguns outros casos limites na biblioteca e está trabalhando ativamente para corrigi-los no futuro próximo. Para mais informações, há uma seção sobre isso no FAQ Ocaml.
Módulos e capitalização
O Ocaml possui um sistema de módulo muito interessante. Em suma, os módulos são usados para agrupar definições relacionadas e podem ser arbitrariamente aninhados. Curiosamente, os arquivos também se tornam módulos, e um dos meus primeiros erros foi relacionado à sua capitalização ao abrir um módulo de um arquivo diferente.
Como parte do ReKeys, eu defino um arquivo chamado dom_utils.re para agrupar certas definições relacionadas à interação com DOM e eventos. Ao tentar abrir esse arquivo para consumo em outro arquivo, não consegui fazê-lo funcionar.
O motivo é que o módulo fornecido por um arquivo é reconhecido pelo compilador com a primeira letra (e somente a primeira letra) maiúscula. Então, domUtils.re torna-se DomUtils, mas dom_utils.re torna-se Dom_utils, e eu estava tentando abrir o Dom_Utils. Esse é um daqueles erros que nunca mais voltarei a fazer, mas foi uma dor de cabeça por um tempo!
Assinaturas de tipo inline
Tendo tentado outras linguagens na família ML, como Haskell, Elm ou PureScript, lutei inicialmente com a forma de anotar os tipos de minhas definições. Em Haskell, por exemplo, os tipos podem ser anotados acima da implementação de uma função, como abaixo:
foo :: Int -> Int foo x = x + 1
No entanto, em Ocaml/Reason, anotar a função foo seria feito inline ou em um arquivo de interface .rei. Exemplo:
/* my_file.rei */ let foo: int => int; /* inline, in a my_file.re file */ let foo: int => int = fun x => x + 1;
Pensamentos finais
No geral, minha experiência com Reason foi incrivelmente boa. Eu adoro como o compilador atua como alguém constantemente olhando por cima do meu ombro me dizendo as maneiras incríveis como posso estragar o que eu estou fazendo.
A comunidade Reason no Discord é extremamente útil e tem sido muito paciente com minhas constantes perguntas de novato sobre qualquer coisa referente a Ocaml/Reason.
Eu estou animado para continuar mexendo com Reason e, eventualmente, construir algo mais sério. Enquanto isso, sugiro que você o experimente.
O código para ReKeys é gratuito e open source no GitHub. Por favor, tweet para @anmonteiro90 com quaisquer dúvidas/comentários sobre o código ReKeys e/ou este artigo!
Bom hacking!
***