diff --git a/.gitignore b/.gitignore index f174344..677dfda 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ _book +.vscode diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..638a954 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "workbench.colorTheme": "Visual Studio Light" +} \ No newline at end of file diff --git a/pt-br/.gitignore b/pt-br/.gitignore new file mode 100644 index 0000000..f174344 --- /dev/null +++ b/pt-br/.gitignore @@ -0,0 +1 @@ +_book diff --git a/pt-br/Makefile b/pt-br/Makefile new file mode 100644 index 0000000..eae018f --- /dev/null +++ b/pt-br/Makefile @@ -0,0 +1,2 @@ +pdf: + gitbook pdf diff --git a/pt-br/README.md b/pt-br/README.md new file mode 100644 index 0000000..7449592 --- /dev/null +++ b/pt-br/README.md @@ -0,0 +1,4 @@ +![Pragmatic Functional JavaScript](./cover.jpg) + + + diff --git a/pt-br/SUMMARY.md b/pt-br/SUMMARY.md new file mode 100644 index 0000000..a1a95e1 --- /dev/null +++ b/pt-br/SUMMARY.md @@ -0,0 +1,71 @@ +# Sumário + +* [1. Introdução](introduction.md) + * [O que significa "pragmatismo"?](introduction.md#o-que-significa-pragmatismo) + * [A segunda chance](introduction.md#a-segunda-chance) + * [Menos é mais](introduction.md#menos-é-mais) + * [Ferramentas](introduction.md#ferramentas) +* [2. Roots of the evil](roots-of-the-evil.md) + * [Null considered harmful](roots-of-the-evil.md#null-considered-harmful) + * [Mutability can kill your hamster](roots-of-the-evil.md#mutability-can-kill-your-hamster) + * Take care with side-effects + * [Type coercion is a bad boy](roots-of-the-evil.md#type-coercion-is-a-bad-boy) + * Loops are so 80's + * The Hadouken effect + * [Somebody stop this!](roots-of-the-evil.md#somebody-stop-this) +* [3. Meet ESLint](meet-eslint.md) + * [Restricting imperative syntax](meet-eslint.md#restricting-imperative-syntax) + * Plugins to the rescue +* [4. Modules](modules.md) + * The SOLID equivalence + * Top-level declarations +* [5. The power of composition](the-power-of-composition.md) + * Thinking in functions + * Currying and partial application + * Point-free programming + * Piping and composing + * Combinators + * Lenses +* [6. Types](types.md) + * Why types matter + * Flow is your friend + * Don't abuse polymorphism + * Algebraic data types +* [7. Transforming values](transforming-values.md) + * Lists + * Objects + * Functions +* [8. Monads, monoids and functors](monads-monoids-and-functors.md) + * What the hell is a monad? + * Dealing with dangerous snakes + * Handling state + * Exceptions are not the rule +* [9. Async programming](async-programming.md) + * So you still don't understand promises? + * Futures + * Tasks + * Working with processes + * Generators and lazy evaluation +* [10. Welcome to Fantasy Land](welcome-to-fantasy-land.md) + * Unicorns and rainbows + * Static Land +* [11. Hacking the compiler](hacking-the-compiler.md) + * Extending Babel + * Sweet macros +* [12. A bit of theory](a-bit-of-theory.md) + * [Lambda calculus](a-bit-of-theory.md#lambda-calculus) +* [13. Functional languages targeting JavaScript](functional-languages-targeting-javascript.md) + * [LiveScript](functional-languages-targeting-javascript.md#livescript) + * PureScript + * ReasonML + * Elm + * ClojureScript +* [14. Solving real world problems](solving-real-world-problems.md) + * Integrating with external libraries + * Validating data + * Playing with files + * Network requests + * Testing +* [15. Final considerations](final-considerations.md) + * What should I learn now? + diff --git a/pt-br/a-bit-of-theory.md b/pt-br/a-bit-of-theory.md new file mode 100644 index 0000000..e69de29 diff --git a/pt-br/book.json b/pt-br/book.json new file mode 100644 index 0000000..d45cbb6 --- /dev/null +++ b/pt-br/book.json @@ -0,0 +1,11 @@ +{ + "title": "Pragmatic Functional JavaScript", + "description": "Real world functional programming inside JavaScript environment", + "structure": { + "readme": "introduction.md" + }, + "pdf": { + "fontSize": 15, + "fontFamily": "Quattrocento" + } +} diff --git a/pt-br/book.pdf b/pt-br/book.pdf new file mode 100644 index 0000000..faa8edc Binary files /dev/null and b/pt-br/book.pdf differ diff --git a/pt-br/cover.jpg b/pt-br/cover.jpg new file mode 100644 index 0000000..5eec7d1 Binary files /dev/null and b/pt-br/cover.jpg differ diff --git a/pt-br/cover_small.jpg b/pt-br/cover_small.jpg new file mode 100644 index 0000000..3c2603a Binary files /dev/null and b/pt-br/cover_small.jpg differ diff --git a/pt-br/functional-languages-targeting-javascript.md b/pt-br/functional-languages-targeting-javascript.md new file mode 100644 index 0000000..9584d85 --- /dev/null +++ b/pt-br/functional-languages-targeting-javascript.md @@ -0,0 +1,12 @@ +## Functional languages targeting JavaScript + +If you are still not convinced about using JavaScript as a functional language, but enjoys the environment it provides and/or needs to do web or server development with it, then there are several alternative languages that encourages functional programming better than JavaScript and compile to it. You may think, if it compiles to JavaScript, why not writing JavaScript? Because languages provide abstractions to make problem solving easier. This would be the same thing about arguing about writing Assembly because "languages compile to it". There are almost as many languages that compile to JavaScript as there are JavaScript frameworks and libraries. + + + +## LiveScript + +CoffeeScript is for Ruby as LiveScript is for Haskell. LiveScript is a functional language with strong roots on Haskell and F\# with dynamic type checking that compiles to pure and mappable JavaScript. It's very useful for prototyping and data transformation. It provides a standard library called `prelude-ls` with lots of functions to handle lists, objects and other data structures with focus on composition and immutability, but still allows everything that JavaScript does, such as loops and random effects \(not that you should use them\). LiveScript is a fork of Coco language, an indirect dialect of CoffeeScript, but it is a lot more expressive. It also provides source-maps to allow debugging on VSCode, Chrome or Firefox without headache or suffering. + + + diff --git a/pt-br/introduction.md b/pt-br/introduction.md new file mode 100644 index 0000000..ab21633 --- /dev/null +++ b/pt-br/introduction.md @@ -0,0 +1,89 @@ +# Introdução + +Este livro está separado em 15 capítulos com sub-seções específicas: + +1. **Introdução**: Este capítulo lhe dá uma breve introdução sobre o desenvolvimento de software pragmático, abordando a história e razão da programação funcional e como é aplica-la ao desenvolvimento de software moderno. +2. **Origem do mal**: apresenta características de linguagem que são mais prejudiciais do que benéficas e depois se concentra em alternativas para resolver os problemas que elas apresentaram. +3. **Conheça o ESLint**: mostra como encorajar a escrita do código funcional e restringir os recursos prejudiciais da linguagem usando uma ferramenta específica para isso. +4. **Módulos**: focado em como organizar o código modular e as funções de acordo com seu domínio e estruturar a arquitetura de diretórios do seu programa. Existe um foco especial no código modular, código que não é específico para o programa, mas que pode ser facilmente reutilizado e ajudá-lo a escrever menos. +5. **O poder da composição**: aborda o que realmente é a programação funcional e mostra como criar coisas mais complexas, compondo muito simples. É definitivamente como jogar LEGO! +6. **Types**: provides an overview about how a type system behaves and tools for static type checking on JavaScript in order to reduce the number of bugs. It also provides a different overview about static type system, different from what is presented in most courses and tutorials. +6. **Tipos**: fornece uma visão geral sobre como um sistema de tipo se comporta e ferramentas para verificação de tipo estático em JavaScript para reduzir a quantidade de erros. Ele também fornece uma visão geral diferente sobre o sistema de tipo estático, diferente do que é apresentado na maioria dos cursos e tutoriais. +7. **Transforming values**: talks about common data structures transformations and functions that help us modeling transformations and working with immutable data structures. We'll be using a library called Ramda to present it in practice. +7. **Transformando valores**: fala sobre transformações de dados e funções que nos ajudam a modelar transformações e trabalhar com estruturas de dados imutáveis. Estaremos usando uma biblioteca chamada Ramda para apresentá-la na prática. +8. **Monads, monoids e functors**: pode parecer um pouco teórico, mas irá apresentar, juntamente com os conceitos dos termos, o uso prático deles e a importância deles no design de um programa funcional e como eles nos ajudam a lidar com erros e lidar com o perigo que exite mundo a fora. +9. **Programação assíncrona**: é uma visão geral sobre como lidar com ações dependentes do tempo e computações assíncronas. Falaremos sobre promises, futures, generators e a task monad. +10. **Bem-vindo à Terra da Fantasia**: mostra o que é a Terra da Fantasia e como ajuda bibliotecas funcionais diferentes a interagir facilmente e trabalhar em conjunto e mostra algumas bibliotecas que são compatíveis com esta especificação. +11. **Hackeando o compilador**: fornece uma visão geral sobre o Babel e as ferramentas préprocessadoras para JavaScript que nos permitem extender a linguagem para reduzir o tamanho e facilitar o modelamento de nossos problemas. Apresentaremos como escrever plugins no compilador e usar já existentes para escrever um código melhor. +12. **Um pouco de teoria**: é definitivamente a parte mais teórica do livro. Apresentamos as raízes da programação funcional e possivelmente conceitos avançados. +13. **Linguagens Funcionais que visam o JavaScript**: apresenta quatro linguagens que compilam para JavaScript e têm uma boa interoperabilidade com ele, mas com foco no paradigma funcional. Alguns são mais restritivos do que outros, no entanto, com a restrição vem a segurança e a precicabilidade. +14. **Resolvendo problemas do mundo real**: presents common daily problems and functional approaches, step by step, to solve them. It is not only about solving problems, but solving problems in such way that they will generate less problems later. +14. **Resolvendo problemas do mundo real**: apresenta problemas comuns diários e abordagens funcionais, passo a passo,para resolvê-los. Não se trata apenas de resolver problemas, mas resolver problemas de tal forma que eles gerarão menos problemas mais tarde. +15. **Considerações Finais**: é o nosso "adeus". Não é a conclusão, porque as abordagens de desenvolvimento de software estão evoluindo muito rápido, e assumindo que uma maneira específica de fazer o trabalho é o melhor para todos os tempos é definitivamente tolo. + +A maioria das partes deste livro são independentes, para que você possa ler capítulos na ordem que você preferir, e a ordem que definimos aqui é apenas uma sugestão (exceto para as considerações finais, é claro). + +## O que significa "pragmatismo"? + +Pragmatismo, substantivo, uma abordagem **prática** para problemas e assuntos. Não há nenhuma palavra que possa descrever este livro melhor. Vamos nos concentrar em aplicações práticas da bela e encantadora teoria construída em torno da programação funcional. Este livro é feito para pessoas com conhecimentos básicos sobre programação de JavaScript; você definitivamente não deveria ter habilidades excepcionais para entender as coisas aqui escritas: é feito para ser prático, simples, conciso e depois disso, exceto você, para poder escrever aplicativos do mundo real usando o paradigma funcional e, finalmente, dizer "Eu **faço** o trabalho com programação funcional! ". Este livro pode ser complexo para iniciantes e triviais para programadores avançados. Ele é projetado pensando no programador usual que usa o JavaScript diariamente para construir qualquer tipo de aplicativo, mas que já **tem** familiaridade com o JavaScript e está aberto à mentalidade funcional. Se você está começando a codificar agora, existem melhores alternativas para isso, como *Structure and Interpretation of Computer Programs* e *How to Design Programs*. + +Quando possível, forneceremos o problema que estamos tentando resolver com implementações e técnicas alternativas em outros paradigmas. A programação é feita para resolver problemas, mas às vezes resolver um problema pode gerar vários outros pequenos problemas, e é aqui que tocaremos; É isso que tentaremos evitar. Antes de continuar, precisamos estabelecer algumas premissas: + +* **As linguagens de programação não são perfeitas**: sério. Elas são construídas e projetadas por humanos, e os humanos não são perfeitos \(longe disso!\). Eles podem conter falhas e recursos arbitrariamente definidos, no entanto, na maioria das vezes, há uma explicação razoável sobre a "gambiarra". + +* **A resolução de problemas pode gerar outros problemas**: Se você está preocupado apenas com "fazer as coisas", isso pode ser um pouco controverso para você. Quando você resolve um problema, tenha em mente que sua solução não é livre de apresentar problemas que outras pessoas terão que resolver mais tarde. Estar aberto a críticas é bom aqui; É assim que a tecnologia evolui. + +* **A ferramenta certa para o trabalho certo**: isso é pragmatismo. Escolhemos a ferramenta que resolve o problema e introduz o menor número de efeitos colaterais. Os bons programadores analisam os trade-offs. Há muitas linguagens de programação publicadas e dezenas de paradigmas, e eles não são criados/descobertos apenas porque "alguém gosta de escrever dessa maneira" ou "alguém quer ter seu nome em uma linguagem de programação" \(pelo menos na maioria das vezes\) , mas porque surgem novos problemas. É sensível, por exemplo, usar Erlang em sistemas telefônicos, Agda em provas matemáticas e Go em sistemas concorrentes, mas é definitivamente insano usar Brainfuck no desenvolvimento web e PHP no desenvolvimento de compiladores! + + +### O autor + +Marcelo Camargo é um simpático programador brasileiro e um dos principais evangelistas do paradigma no Brasil. Ele é o designer da linguagem de programação Quack e colaborador ou mantenedor de dezenas de projetos open-source, como a primeira versão não oficial do Skype para Linux e melhorias na linguagem PHP. Ele ama a teoria do tipo, as capivaras e tem um gatinho preto fofo que quase sempre está com ele enquanto escreve. Você pode encontrá-lo no GitHub como [`/haskellcamargo`](https://github.com/haskellcamargo) ou escreva-lhe uma carta em [marcelocamargo@linuxmail.org] (marcelocamargo@linuxmail.org). + + +## A segunda chance + +> E Deus disse: "que haja funções", e havia funções. + +No começo, os computadores eram muito lentos, muito mais lentos do que o Android Studio em sua máquina com 2GB de RAM! Quando os primeiros computadores físicos apareceram e as linguagens de programação começaram a ser projetadas e implementadas, havia principalmente 2 mentalidades: + +1. Comece pela arquitetura de Von Neumann e **adicione a abstração**; +2. Comece a partir da matemática e **remova a abstração**. + +Quando tudo começou, lidar com altos níveis de abstração era muito difícil e dispendioso, a memória e o armazenamento eram muito pequenos, então as linguagens de programação imperativas obtiveram muito mais visibilidade do que as funcionais, pois as linguagens imperativas tinham um nível de abstração inferior que era uma maneira mais fácil de implementar e mapear diretamente para o hardware. Poderia não ser a melhor maneira de projetar programas e expressar idéias, mas pelo menos era mais rápido para executar. + +Mas os computadores melhoraram muito, e a programação funcional finalmente conseguiu sua merecida chance! A programação funcional não é um conceito novo. Estou falando sério, é muito velho e veio diretamente da matemática! Os conceitos fundamentais e o modelo computacional funcional vieram mesmo antes que os computadores físicos existissem. Tinha suas origens no cálculo lambda, e era, inicialmente, apenas um sistema formal desenvolvido na década de 1930 para investigar computabilidade. + +Muitas linguagens de programação modernas suportam programação funcional bem. Até Mesmo Java se rendeu a isso e implementou expressões lambda e streams. A maioria de vocês programa em linguagens que foram criadas; Quero mostrar-lhe o que foi descoberto. + + +### Por que a programação funcional? + +Se a programação imperativa e outros paradigmas, como a orientação do objeto, eram bons o suficiente, por que precisamos aprender uma nova maneira de codificar? A resposta é: sobrevivência. A orientação a objeto não pode mais nos salvar do monstro da nuvem. Problemas mais complexos surgiram e a programação funcional se encaixa muito bem. A programação funcional não é "outra sintaxe", como algumas pessoas pensam; É uma outra mentalidade e uma maneira declarativa de resolver problemas. Embora na programação imperativa você especifique etapas e como as coisas acontecem, na programação declarativa \(funcional e lógica\) você especifica o que tem que ser feito e o computador deve decidir a melhor maneira de fazer isso. Nós evoluímos muito para fazer o trabalho que um computador pode fazer centenas de vezes melhor que nós. + +#### Testabilidade e manutenção + +As bases de código modulares e funcionais são muito mais fáceis de testar e obter uma cobertura elevada nos testes de unidades. As coisas são muito bem isoladas e independentes e, seguindo todos os princípios principais, você obtém programas compostos que funcionam bem juntos e têm menos erros. + +#### Paralelismo + +Isso é realmente variável com a implementação, mas em linguagens que podem acompanhar todos os tipos de efeitos, você obtém paralelismo e a possibilidade de agrupar seu programa sem nenhum custo. + +#### Otimização + +As linguagens funcionais tendem a ser muito mais fáceis de otimizar e são mais previsíveis para os compiladores. Conhecer todo o tipo de coisas que podem ser vistas em um programa dá a possibilidade ao compilador de conhecer a semântica do seu código antes mesmo de executá-lo. Haskell pode ser ainda mais rápido que C se você escrever código idiomático! O principal mecanismo de JavaScript, V8, investiu amplamente em otimizações para o paradigma funcional. + +## Menos é mais + +Ter muitas maneiras de fazer um trabalho e resolver um problema no mesmo contexto é sempre bom, certo? Bem, nem sempre. Se você pegar a maioria das linguagens de programação que são amplamente utilizadas pelo mercado, então você tem uma linguagem funcional - e isso é válido também para o JavaScript. O JavaScript tem fortes laços com o Esquema e tem o potencial perfeito para ser uma excelente linguagem funcional. Remova laços, mutabilidade, referências, declarações condicionais, exceções, etiquetas, blocos e você praticamente possui um dialeto OCaml digitado dinamicamente. Estou falando sério, você pode até definir funções em JavaScript sem dar importância à ordem em que ocorrem, assim como OCaml em Haskell faz - isso é o que podemos chamar de hoisting e nós veremos como aproveitar isso nos próximos capítulos. + +Não seja avarento. Você realmente precisa de todas as diferentes construções de linguagem não endereçadas? Nos capítulos deste livro, descartaremos uma grande parte do JavaScript e nos concentraremos apenas em um subconjunto expressivo: funções e ligações, é tudo o que precisamos por enquanto! Antes de aprender a programação funcional com JavaScript, primeiro você terá que pensar em desaprender algumas coisas. Isso é necessário para evitar vícios de linguagem e estimular seu cérebro para resolver problemas de maneira declarativa. Por enquanto, você terá que confiar, mas no decorrer deste livro, você verá como tudo faz sentido e se encaixa no propósito. + +## Ferramentas + +Nós nos concentraremos mais na semântica do programa e na correção do que na execução, mas se você realmente quiser aprender, apenas a leitura deste livro não será suficiente. + + + + + diff --git a/pt-br/meet-eslint.md b/pt-br/meet-eslint.md new file mode 100644 index 0000000..4ddaa33 --- /dev/null +++ b/pt-br/meet-eslint.md @@ -0,0 +1,10 @@ +# Meet ESLint + +Using a linter is a nice way to help you avoiding mistakes and encouraging a standard coding style. There is an excelent tool called ESLint for that. We will be using it in these series to restrict some language features while encouraging others. + +## Restricting imperative syntax + +We will configure the linter to restrict imperative syntax to avoid relapses. The mindset used in functional programming is different, simpler than imperative, so we can eliminate language features that would cause confusion and that have good functional replacements. + + + diff --git a/pt-br/monads-monoids-and-functors.md b/pt-br/monads-monoids-and-functors.md new file mode 100644 index 0000000..a09bfaa --- /dev/null +++ b/pt-br/monads-monoids-and-functors.md @@ -0,0 +1,6 @@ +# Monads, monoids and functors + +I'm pretty you sure you already have heard about the term "monad". A lot of people talk about them, but a few know what they really mean and how they can fit into functional programming. We'll be focusing on the practical approach of monads, but give a gentle introduction to the theory. The most advanced theory can still be found in the chapter 12 of this book. + + + diff --git a/pt-br/roots-of-the-evil.md b/pt-br/roots-of-the-evil.md new file mode 100644 index 0000000..28bf788 --- /dev/null +++ b/pt-br/roots-of-the-evil.md @@ -0,0 +1,142 @@ +# Roots of the evil + +## Null considered harmful + +And by `null`, we also mean `undefined`. It is hard to see a programmer who never had any sort of problems with null references, null pointers or anything that can represent the absence of a value. For JavaScript programmers, `undefined is not a function`, for the C\# young men in suits, `NullReferenceException`, and for unlucky one who use need to use Java, the classic `java.lang.NullPointerException`. Do you think we really need `null` as a special language construct? In this point, there is also a consensus between functional programmers and object-oriented programmers: `null` was a secular mistake. + +### A brief history + +Null references were introduced in ALGOL-W programming language decades ago; 1964 to be specific. They hadn't any special purpose except they were considered "easy to implement" by the language designers, and a lot of modern languages implemented it for the same reason ─ and it gone viral. At that time, most of the softwares, including the compiler, were written in machine code with little or no abstraction. But what is wrong with `null`? + +### \(too many\) runtime exceptions + +I don't mean runtime exceptions would be abolished if `null` were, but they would reduce a lot for sure. Unexpected exceptions due no null references are very common in the life of Java, JavaScript, C, Go and C\# programmers ─ and we could avoid that with specific techniques. We can't have exceptions involving `null` values if we don't have `null` values. + +### It increases complexity + +When you have to compare for null to avoid runtime errors, your code logic forks and creates a new path of possibilities. If you use lots of `null` values, the chance of having spaghetti code that becomes hard to maintain is really big. Object-oriented languages recommend the _null object pattern_, while functional languages use monads for that. Luckily, there are lots of libraries and monadic implementations for JavaScript to abstract and avoid this problem. We'll see monads in details and how to properly handle `null` later ─ for now we'll be presenting the problems and seeking the solution will be a task for the next chapters. + +### Unpredictable types + +Why would you return `null` in a function that retrieves the list of users of the database when I can just return the **empty representation** of the expected type? ─ an empty array in this situation. The fact is that `null` can inhabit **any** type, and this makes the task of debugging a lot harder. Which one is more pragmatic? + +```js +const showUsers = () => { + const users = getUsers() + if (users !== null) { + users.forEach(console.log) + } +} +``` + +```js +const showUsers = () => getUsers().forEach(console.log) +``` + +Don't make it complex when you can make it simple. + +### True, false ...and null!? + +Unless you have a **very** good excuse, don't return `null` when all you need to do is giving a simple boolean answer. First thing: `null` is not `false`, `null` is the absence of value, and in this case we don't have a boolean representation, but a three-state model. Booleans should never be nullable \(or they aren't booleans at all\) ─ and `null` is not the same as `false` and not even supposed to be. + +## Mutability can kill your hamster + +One of the pillars of functional programming is immutability, and changing things is a very common thing in imperative and object-oriented programming languages, but how one can model computations and problems without even being allowed to have variables? + +Mutability is about showing the computer **how** to solve your problem and not presenting out declaratively **what** is the problem that it should solve. + +Before presenting how we can do it, let's first examine why mutability is evil and you should avoid it when possible and sensible if you care about the life and health of your hamster. This is definitely not a rant about mutability in general, but an overview of the problems that are undeniably common in real world projects. There are situations where mutability is necessary, but they are the exception, not the rule. + +### Mutable data is inherently complex + +And mutability without explicit control is what makes software development difficult. The control flow of your program takes more possible paths and more things to worry about. When maintaining code bases with lots of mutable or global variables and references, there are not warranties that touching and changing a function will not present side-effects in other part of the program that may be completely unrelated. Functions with only input and output give you warranty that they will not affect other parts of the program and are predictable. Worrying about program safety should be a work of the compiler, not yours. The programmer should worry about problem modeling and the only errors with which they should worry about should be from business logic, but most mainstream languages transfer their work to the depressive programmer. + +### Multithreading is hard + +If you believe that imperative languagens and things which are closer to Assembly are better for distributed systems, you are wrong, and increasingly wrong. Immutable and predictable code is inherently easier to optimize to run in multiple cores and threads because the compiler knows that it can safely run different parts of the program independently knowning that there is no interdependence among them. A function that has some input and aways the same output and that doesn't touches parts of the program it shouldn't or emit side-effects is always thread-safe and optimizable. + +Another problem with mutable state is when you deal with server-side development with a stateless server. Running your application in clusters \(multiple cores or machines\) with a stateful server becomes a major source of headache because the mutable state of the server is not shared across all the possible instances of the application. The absence of a global mutable state is what allows Haskell to be so optimizable. Erlang and Elixir store and share this state using the process calculus \(like π-calculus\). + +### Loss of reversibility + +Reversibility matters a lot. Since 2015, new tools for front-end development have emerged and a large part of them is about state control and reversibility, such as React and Vue. Reversibility is about having the control of your program and being able to replicate the point of a program based purely on it's current state. This also makes debugging and finding errors a lot easier because not reproducing errors can no longer be an excuse. When you have reversibility and state control, complexes things become trivial, such as restoring the program state on restarting it or implementing "undo" and "redo" operations. + +### Debugging can be tiresome + +And I'm not joking. Debugging becomes still harder when you are dealing with multiple processes and asynchronous programming. Did you ever wonder how in the world that variable suddenly had its value changed? When you combine mutability with nullity, you create a dangerous monster. + +### References may be a problem + +And the problem increases when you add mutable references; they are, at first, hard for compiler optimization and creates a snowball where any point of the application that receives a reference is able to mutate the value hold by the variable. References are very useful in some situations, but unless you really need to use them and you know what you are doing, avoid them JavaScript has a special problem where some methods work on references instead of values, and you can easily lose the control of the situation: + +```javascript +const list = [8, 3, 1, 2, 7, 4] +// The sorted list +console.log(list.sort()) // [1, 2, 3, 4, 7, 8] + +// Then original list... oh wait! +console.log(list) // [1, 2, 3, 4, 7, 8] +``` + +So, if in any point of the application a function that is called to work with the list decides to sort the values, it will mess up with your original data and increase the possibility of a wrong or unexpected computation. Some functions that operate on arrays to keep distance: + +* `copyWithin` +* `fill` +* `pop` +* `push` +* `reverse` +* `shift` +* `sort` +* `splice` +* `unshift` + +They are documented in the Mozilla Developer Network in the section "[Mutator methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/prototype#Mutator_methods)" of the `Array` object. + +Our computers are powerful enough to deal with immutable data transformation without major overheads, that are lots of libraries that do that (but you might not need them), so there is almost no reason to be concerned with micro optimizations that will already occur in compile time. Yes, compile time. The most famous implementations of JavaScript, such as the one which runs on Chrome and Node are compiled (and not directly interpreted) to native machine code right when the program is "started", this is known as JIT ─ Just in time compilation, and then the compiled program executes. + +## Type coercion is a bad boy + +While static typing helps avoiding mistakes and unexpected behaviors, type coercion helps losing the control about your data values and types. Type coercion means that when the operands of an operator have different types, then they are converted to an equivalent and acceptable value by that operator. For instance, when you do: + +```js +1 == true +``` + +This is `true` only because, as longer as there is no comparison for different types, `true` on the right side is converted to a number \(based on `1` in the left side\), in this case, `true` becomes `1`. The operator `===` prevents this conversion from happening, and it is what we will be using from this point. + +The type system of a programming language defines what types of data can exist in the language and how operations can be applied to them, and this sort of thing exist to prevent the programmer from shooting theirself on the foot. Type coercion is about **implicitly** converting incompatible values when there is no valid operation for that type of value. + +In languages like Python, even with dynamic typing, operations like `"foo" + 1` will emit a runtime error: + +```python +>>> "foo" + 1 +Traceback (most recent call last): + File "", line 1, in +TypeError: cannot concatenate 'str' and 'int' objects +``` + +And this helps preventing a lot of bugs that would be caught only in distant point of the program. Type coercion is a misnomer, as long as values have no types in the sense of static typed languages, but it is a definition of how different values interact. The ECMAScript specification about type coercion is really big; there are lots of rules and exceptions and trusting on these conversions is a fatal error. + +This is a major source of bugs in JavaScript programs because there is no **sensible** nor **consistent** specification of how these values should interoperate and behave, but empirical and variant ones, or do you expect logically that `[] + {}` is `[object Object]` and `{} + []` is `0`? I don't think so. + +## Somebody stop this! + +There are a lot of articles about the `this` keyword in JavaScript, and **this** was one of the worst design issues of the language. Some people argue that there would be names that express better the concept of `this`, like `potatoes`. Even JavaScript programmers with years of experience get confused about it and it is a common source of mistakes among them. There are several different ways to set the value of `this` inside a function, such as calling a method from an object, calling a function alone, using `call`, `apply` or even using `new` to create an instance. It's really a handyman keyword. Telling the behavior of a program piece only looking at it when it has `this` is not as easy as it is with pure functions because you need to worry and care about the **context** of call of that function. It also has different behaviors when using `function` keyword and `() =>`, the fat-arrow, which captures the top context instead of creating another, making the use of the two forms of declarations of anonymous functions not interchangeable. + +### Behaviors of this + +#### Method call + +```js +const person = { + fullName: 'Mr. Pickles', + sayName: function () { + console.log(`Hello, my name is ${this.fullName}!`) + } +} + +person.sayName() // Hello, my name is Mr. Pickles! +``` + +Note that using `() =>` instead of `function` would capture the top `this`, making `this.fullName` be `undefined` in this situation. + diff --git a/pt-br/styles/pdf.css b/pt-br/styles/pdf.css new file mode 100644 index 0000000..3a06d39 --- /dev/null +++ b/pt-br/styles/pdf.css @@ -0,0 +1,7 @@ +p, blockquote, ul, ol, dl, table, pre { + text-align: justify; +} + +code { + font-family: Inconsolata !important; +} diff --git a/pt-br/types.md b/pt-br/types.md new file mode 100644 index 0000000..8ea9c60 --- /dev/null +++ b/pt-br/types.md @@ -0,0 +1,16 @@ +# Types + +JavaScript by default doesn't provide support for static type or even runtime type checking. By having type coercion, all the syntactic valid programs are accepted and type errors will only be caught in runtime. For the sake of sanity, there are good tools we can use to make JavaScript code safer and identify most of the runtime errors of a program before they happen, I mean at compile time, like Flow or even TypeScript, the JavaScript superset. + +## Why types matter + +Do we really need types? At first, this should be an obligation of the compiler; it should be its responsability to ensure that your program is correct and let you worry only about the logic, but this is not what happens on the most popular programming languages. You might not need static type checking, but, for sure, having it will help you writing programs that are more correct and safer, avoiding a lot of possible errors that would only happen in specific situations when executing your program. In fact, static type checking will not replace unit tests at all, but will replace the sort of them that are applied to inputs of invalid types. + +When talking about type checking, most people remember about Java, but this is definitely a terrible example of how a type system should be. Seriously, the type system implemented in Java forces you to declare things that the compiler already knows and accepts invalid programs because it is not well designed to deal with a thing we will call _subtyping_. In the section 12, "A bit of theory", we will give you a gentle introduction to type theory; we will not focus specifically on Java, but in systems that can be implemented in the subset of functional languages and explain how type inference works and why most of the languages have awful type systems that make a lot of people hate static typing. If you say you hate static typing, I'm 99% sure you don't hate static typing, but having to write type signature for obvious things and having to waste timing making the work that the compiler should do. + +## Flow is your friend + +Hopefully, to save us from the world of badly-typed programs, we have Flow. + + + diff --git a/pt-br/welcome-to-fantasy-land.md b/pt-br/welcome-to-fantasy-land.md new file mode 100644 index 0000000..0258f18 --- /dev/null +++ b/pt-br/welcome-to-fantasy-land.md @@ -0,0 +1,49 @@ +# Welcome to Fantasy Land + +## Unicorns and rainbows + +Isn't that cute and wonderful? Fantasy Land is a specification for algebraic JavaScript, that is, the specification of how algebraic structures should be interoperable in the JavaScript environment. This means most part of JavaScript libraries and tools with focus in functional programming will follow these laws and specification, making them easily interoperable. This is the theory that will lead to a pragmatic and standardized practic. + +But first, how can we define an algebra? + +* **A set of values**: like primitive numbers, strings or even other data structures. +* **A set of operators**: that can be applied to values. +* **A set of laws**: the operations applied to these values must obey. + +Each Fantasy Land algebra is a separate specification. Some algebras may depend on other algebras. The JavaScript primitives also have equivalents to some of these algebras, as we will see in some occasions. The specification warrants that values that satisfy to specific algebras can be safely replaced by other values that also respect them. For example, we can have: + +* One list can be replaced by another if they have the same length. +* Two objects have the same keys and their values have the same or compatible types. +* Two functions have equivalent output types for equivalent input types. + +### Understanding type signatures + +We'll be using a notation similar to Haskell type signatures to express the types that the algebras must satisfy, where: + +* `::` means "is a member of". + * `e :: t` is the same as "the expression `e` is member of type `t`". + * `true :: Boolean` means that "`true` is a member of type `Boolean`". + * `42 :: Integer, Number` means that "`42` is a member of type `Integer` and type `Number`". +* New types can be created via type constructors. + * Where type constructors can take zero or more parameters. + * In Haskell, `True` is a type constructor that yields a `Bool` and takes no parameters. + * `Array` is a type constructor that takes one parameter. + * `Array Number` is the type of any array that holds only numbers, like `[1, 2]`. + * Types can be nested. `Array (Array Boolean))` is the type of all arrays that have arrays of booleans, like `[[true], [false, true], []]`, where `[]` can be seen as an array compatible to any type parameter. +* Lowercase letters stand for type variables: + * Type variables can take any type unless they have constraint restrictions, as we'll see bellow. + * `[]` can be seen as `Array a` for example, where `a` can be `String`, `Number` or any other type. +* `->`, the arrow, stands for function type constructor. + * `->` is an infix binary type constructor that takes the input type on the left and output type on the right. + * The left type of `->` can be a grouping for functions that take more than one parameter, for example, `(Number, Number) -> Number` is a function that receives two numbers and returns another. + * Parentheses on the left of `->` are optional for unary functions and obligatory for the rest. + * Functions that take no arguments can be represented by the *unit* type `()`. + * `a -> a` is a function that receives a parameter and yields a value of the same type. + * `Array String -> Array Number` is a function that receives an array of strings and yields an array of numbers. + * `(String, String) -> a` is a function that receives two strings and yields anything. + * `() -> ()` is a function that takes no parameters and yields no results. +* `~>`, the squiggly arrow, stands for method type constructor. + * If a function is a property of an object, then it is a method. Methods have implicit type parameters that is the type of the object that holds the property. + * `Object ~> () ~> String` is the signature satisfies by a method that, when applied to the object and without parameters, yields a string, such as `Object.prototype.toString`: `(1).toString`. +* `=>`, the fat arrow, stands for constraints in type variables. + * `Monoid a => a ~> a -> a` stands for a method applied to an object of type `a` that receives another instance of `a` and yields also an `a` where all these values satisfy to the `Monoid` laws. \ No newline at end of file