├── .gitignore ├── package.json ├── contributing.md ├── LICENSE └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "functional-programming-jargons", 3 | "version": "1.0.0", 4 | "description": "Jargon from the functional programming world in simple terms!", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "toc": "roadmarks" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/hemanth/functional-programming-jargon.git" 13 | }, 14 | "author": "hemanth", 15 | "license": "MIT", 16 | "bugs": { 17 | "url": "https://github.com/hemanth/functional-programming-jargon/issues" 18 | }, 19 | "homepage": "https://github.com/hemanth/functional-programming-jargon#readme", 20 | "devDependencies": { 21 | "roadmarks": "^1.6.3" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | # Contribuição 2 | 3 | Este projeto está em construção. Conribuições são muito bem-vindas. 4 | 5 | Dito isso, gostaríamos de manter algumas consistências no decorrer do documento. 6 | 7 | ## Guia de estilo 8 | 1. Cada definição deve incluir pelo meons um exemplo de código em JavaScript. 9 | 1. Definições devem ser escritas usando a linguagem mais simples possível. 10 | 1. Mire nos programadores que não tem experiência em programação funcional. 11 | 1. Valorizamos mais a compreensão do que a precisão. Por exemplo, tudo bem em descrever um functor como um container. 12 | 1. Não abuse dos jargões, mesmo se ele já estiver definido no documento. 13 | 1. Faça links para termos definidos no documento quando for usá-los em uma definição. 14 | 1. Evite textões. 15 | 16 | ## Convenção de código 17 | Seja consistente com os outros exemplos. 18 | 19 | * Prefira arrow functions 20 | * Parênteses ao redor dos argumentos das funções 21 | * Valores de saída nos comentários 22 | * Use ponto-e-vírgula 23 | * Simples e direto 24 | 25 | Esse guia de estilo é um WIP também! Mandem PRs! 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Hemanth.HM 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Jargões da Programação Funcional 2 | 3 | O objetivo desse documento é definir os jargões da programação funcional em inglês simples com exemplos. 4 | 5 | *Isso aqui é um WIP; Sinta-se a vontade para enviar um PR ;)* 6 | 7 | Esse documento usa termos definidos na [Fantasy Land spec](https://github.com/fantasyland/fantasy-land) quando aplicável. 8 | 9 | 10 | 11 | * [Aridade](#aridade) 12 | * [Funções de Ordem Maior (HOF)](#fun%C3%A7%C3%B5es-de-ordem-maior-hof) 13 | * [Aplicações Parciais](#aplica%C3%A7%C3%B5es-parciais) 14 | * [Currying](#currying) 15 | * [Composição de Função](#composi%C3%A7%C3%A3o-de-fun%C3%A7%C3%A3o) 16 | * [Pureza](#pureza) 17 | * [Efeitos Colaterais](#pureza) 18 | * [Idempotente](#idempotente) 19 | * [Estilo Livre de Apontamento](#estilo-livre-de-apontamento) 20 | * [Predicado](#predicado) 21 | * [Contratos](#contratos) 22 | * [Funções Guardadas](#fun%C3%A7%C3%B5es-guardadas) 23 | * [Categorias](#categorias) 24 | * [Valor](#valor) 25 | * [Constante](#constante) 26 | * [Functor](#functor) 27 | * [Functor Apontado](#functor-apontadoo) 28 | * [Levantamento](#levantamento) 29 | * [Transparência Referencial](#transpar%C3%AAncia-referencial) 30 | * [Raciocínio Equacional](#racioc%C3%ADnio-equacional) 31 | * [Avaliação Preguiçosa](#avalia%C3%A7%C3%A3o-pregui%C3%A7osa) 32 | * [Monóide](#mon%C3%B3ide) 33 | * [Monade](#monade) 34 | * [Comonade](#comonade) 35 | * [Functor Aplicativo](#functor-aplicativo) 36 | * [Morfismo](#morfismo) 37 | * [Isomorfismo](#isomorfismo) 38 | * [Setóide](#set%C3%B3ide) 39 | * [Semigrupo](#semigrupo) 40 | * [Dobrável](#dobr%C3%A1vel) 41 | * [Transversável](#travers%C3%A1vel) 42 | * [Assinatura de Tipos](#assinaturas-de-tipo) 43 | * [Tipo de União](#tipo-de-uni%C3%A3o) 44 | * [Tipo de Produto](#tipo-de-produto) 45 | * [Opção](#op%C3%A7%C3%A3o) 46 | 47 | 48 | 49 | 50 | ## Aridade 51 | 52 | O número de argumentos que uma função recebe. Vem das palavras tipo unário, binário, ternário, etc. Essa palavra possui a característica de ser formada por dois sufixos, "-ário" e "-idade". Soma, por exemplo, recebe dois argumentos, portanto é definido como uma função binária ou uma função com aridade dois. Funções assim podem ser chamadas de "Diádica" pelos amantes das raízes gregas ao invés das latinas. Da mesma forma, uma função que recebe um número variável de argumentos é chamada de "variádica", enquanto uma função binária deve possuir dois e apenas dois argumentos, não obstante o currying e a aplicação parcial (veja abaixo). 53 | 54 | 55 | 56 | ```js 57 | const soma = (a, b) => a + b; 58 | 59 | const aridade = soma.length; 60 | console.log(aridade); // 2 61 | 62 | // A aridade de soma é 2 63 | ``` 64 | 65 | ## Funções de Ordem Maior (HOF) 66 | 67 | Uma função que recebe outra função como argumento e/ou retorna uma função. 68 | 69 | 70 | ```js 71 | const filter = (pred, xs) => { 72 | const result = []; 73 | for (let idx = 0; idx < xs.length; idx++) { 74 | if (pred(xs[idx])) { 75 | result.push(xs[idx]); 76 | } 77 | } 78 | return result; 79 | }; 80 | ``` 81 | 82 | ```js 83 | const is = (type) => (x) => Object(x) instanceof type; 84 | ``` 85 | 86 | ```js 87 | filter(is(Number), [0, '1', 2, null]); // [0, 2] 88 | ``` 89 | 90 | ## Aplicações Parciais 91 | 92 | O processo de receber uma função com menor aridade comparada à função original, corrigindo o número de argumentos, é conhecido como aplicação parcial. 93 | 94 | ```js 95 | let sum = (a, b) => a + b; 96 | 97 | // aplicando parcialmente `a` para `40` 98 | let partial = sum.bind(null, 40); 99 | 100 | // invocando com b `b` 101 | partial(2); // 42 102 | ``` 103 | 104 | ## Currying 105 | 106 | O processo de converter uma função que recebe múltiplos argumentos em uma função que os recebe um de cada vez. 107 | 108 | Cada vez que a função é chamada, aceita somente um argumento e retorna uma função que recebe um argumento até que todos sejam passados. 109 | 110 | 111 | 112 | ```js 113 | const sum = (a, b) => a + b; 114 | 115 | const curriedSum = (a) => (b) => a + b; 116 | 117 | curriedSum(40)(2) // 42. 118 | 119 | const add2 = curriedSum(2); // (b) => 2 + b 120 | 121 | add2(10) // 12 122 | 123 | ``` 124 | 125 | ## Composição de Função 126 | 127 | O ato de colocar duas funções juntas para forma uma terceira função onde a saída dessa função é a entrada de outra. 128 | 129 | 130 | ```js 131 | const compose = (f, g) => (a) => f(g(a)) // Definition 132 | const floorAndToString = compose((val) => val.toString(), Math.floor) // Uso 133 | floorAndToString(121.212121) // "121" 134 | ``` 135 | 136 | ## Pureza 137 | 138 | Uma função é pura quando o valor de retorno é determinado apenas pelas suas entradas, e não produz efeitos colaterais. 139 | 140 | ```js 141 | let greet = (name) => "Olá, " + name ; 142 | 143 | greet("Brianne") // "Olá, Brianne" 144 | 145 | ``` 146 | 147 | Em oposição à: 148 | 149 | ```js 150 | 151 | let greeting; 152 | 153 | let greet = () => greeting = "Olá, " + window.name; 154 | 155 | greet(); // "Olá, Brianne" 156 | 157 | ``` 158 | 159 | ## Efeitos Colaterais 160 | 161 | Dizemos que uma função ou expressão tem efeitos colaterais se além de retornar um valor, ela interaja com (lê ou escreve) estados mutáveis eternos. 162 | 163 | ```js 164 | var differentEveryTime = new Date(); 165 | ``` 166 | 167 | ```js 168 | console.log("IO é um efeito colateral!"); 169 | ``` 170 | 171 | ## Idempotente 172 | 173 | Uma função é idempotente se ao reaplicá-la ao seu próprio resultado não produz um resultado diferente. 174 | 175 | ```js 176 | f(f(x)) = f(x) 177 | ``` 178 | 179 | ```js 180 | Math.abs(Math.abs(10)) 181 | ``` 182 | 183 | ```js 184 | sort(sort(sort([2,1]))) 185 | ``` 186 | 187 | ## Estilo Livre de Apontamento 188 | 189 | Esse estilo se define ao escrever funções que não identificam explicitamente os argumentos usados. Geralmente requer [currying](#currying) ou outra [função de ordem maior](#fun%C3%A7%C3%B5es-de-ordem-maior-hoff). Mais conhecido como programação implícita. 190 | 191 | ```js 192 | // Dado 193 | let map = (fn) => (list) => list.map(fn); 194 | let add = (a) => (b) => a + b; 195 | 196 | // Então 197 | 198 | // Não é livre de apontamento - `numbers` é um argumento explícito 199 | let incrementAll = (numbers) => map(add(1))(numbers); 200 | 201 | // Livre de apontamento - A lista é um argumento implícito 202 | let incrementAll2 = map(add(1)); 203 | ``` 204 | 205 | `incrementAll` identifica e usa o parâmetro `numbers`, logo, não é livre de apontamento. `incrementAll2` é escrita combinando funções e valores, não fazendo menção aos seus argumentos. Ela __é__ livre de apontamento. 206 | 207 | Definição de funções livre de apontamento são como funções normais, mas sem `function` ou `=>`. 208 | 209 | 210 | ## Predicado 211 | Um predicado é uma função que retorna verdadeiro ou falso de acordo com um valor dado. Um uso comum de predicados é o callback de filtros de array. 212 | 213 | ```js 214 | const predicate = (a) => a > 2; 215 | 216 | [1, 2, 3, 4].filter(predicate); // [3, 4] 217 | ``` 218 | 219 | ## Contratos 220 | 221 | TODO 222 | 223 | ## Funções Guardadas 224 | 225 | TODO 226 | 227 | ## Categorias 228 | 229 | Objetos com funções associadas que aderem a certas regras. Exemplo: [Monóide](#monoide) 230 | 231 | ## Valor 232 | 233 | Qualquer coisa que possa ser atribuída a uma variável. 234 | 235 | ```js 236 | 5 237 | Object.freeze({name: 'John', age: 30}) // A função `freeze` força a imutabilidade. 238 | (a) => a 239 | [1] 240 | undefined 241 | ``` 242 | 243 | ## Constante 244 | 245 | Uma variável que não pode ser reatribuída após ser definida pela primeira vez. 246 | 247 | ```js 248 | const five = 5 249 | const john = {name: 'John', age: 30} 250 | ``` 251 | 252 | Constantes são [transparentes referencialmente](#transpar%C3%AAncia-referencial). Ou seja, podem ser substituídas pelos valores que representam sem afetar o resultado. 253 | 254 | Com as duas constantes acima, a expressão a seguir vai retornar `true` sempre. 255 | 256 | ```js 257 | john.age + five === ({name: 'John', age: 30}).age + (5) 258 | ``` 259 | 260 | ## Functor 261 | 262 | Um objeto com uma função `map` que adere a certas regras. `Map` executa uma função sobre os valores de um objeto e retorna um objeto novo. 263 | 264 | 265 | Um functor comum no js é `Array` 266 | 267 | ```js 268 | [2, 3, 4].map((n) => n * 2); // [4, 6, 8] 269 | ``` 270 | 271 | Se `func` é um objeto implementando uma função de `map` e `f` e `g` são funções arbitrárias, então diz-se que `func` é o functor se a função map adere às seguintes regras. 272 | 273 | ```js 274 | // identidade 275 | func.map((x) => x) === func 276 | ``` 277 | 278 | e 279 | 280 | ```js 281 | // composição 282 | func.map((x) => f(g(x))) === func.map(g).map(f) 283 | ``` 284 | 285 | Podemos agora ver que `Array` é um functor pois adere às regras do functor. 286 | 287 | ```js 288 | [1, 2, 3].map((x) => x); // = [1, 2, 3] 289 | ``` 290 | 291 | e 292 | 293 | ```js 294 | let f = (x) => x + 1; 295 | let g = (x) => x * 2; 296 | 297 | [1, 2, 3].map((x) => f(g(x))); // = [3, 5, 7] 298 | [1, 2, 3].map(g).map(f); // = [3, 5, 7] 299 | ``` 300 | 301 | ## Functor Apontado 302 | Um functor com uma função `of` que coloca _qualquer_ valor individual naquele functor. 303 | 304 | Implementação em Array: 305 | 306 | ```js 307 | Array.prototype.of = (v) => [v]; 308 | 309 | [].of(1) // [1] 310 | ``` 311 | 312 | ## Levantamento 313 | 314 | Levantamento é tipo um `map`, exceto pelo fato que pode ser aplicado a múltiplos functores. 315 | 316 | Map é o mesmo que um levantamento sobre uma função de um argumento. 317 | 318 | 319 | ```js 320 | lift((n) => n * 2)([2, 3, 4]); // [4, 6, 8] 321 | ``` 322 | 323 | Diferente de map, levantamento pode ser usado para combinar valores de múltiplas arrays. 324 | 325 | ```js 326 | lift((a, b) => a * b)([1, 2], [3]); // [3, 6] 327 | ``` 328 | 329 | ## Transparência Referencial 330 | 331 | Uma expressão que pode ser substituída pelo seu valor sem alterar o comportamento do programa, é dita como referencialmente transparente. 332 | 333 | Vamos supor que temos a função `greet`: 334 | 335 | ```js 336 | let greet = () => "Hello World!"; 337 | ``` 338 | 339 | Qualquer invocação de `greet` pode ser substituida com `Hello World!`, logo `greet` é referencialmente transparente. 340 | 341 | 342 | ## Raciocínio Equacional 343 | 344 | Quando uma aplicação é composta de expressão e desprovida de efeitos colaterais, as verdades sobre o sistema podem ser derivadas de suas partes. 345 | 346 | ## Avaliação Preguiçosa 347 | 348 | Avaliação Preguiçosa é um mecanismo de avaliação chamado conforme necessidade que atrasa a avaliação de uma expressão até que seu valor seja requerido. Em linguagens funcionais, isso permite o uso de estruturas tipo listas infinitas, o que não seria possível normalmente em uma linguagem imperativa onde a sequência dos comandos é significante. 349 | 350 | ```js 351 | let rand = function*() { 352 | while (1 < 2) { 353 | yield Math.random(); 354 | } 355 | } 356 | ``` 357 | 358 | ```js 359 | let randIter = rand(); 360 | randIter.next(); // Cada execução retorna um valor conforme necessário. 361 | ``` 362 | 363 | ## Monóide 364 | 365 | Monóide é um tipo de dado junto de uma função de dois parâmetros que "combina" dois valores do tipo, onde um valor de identidade que não afeta o resultado da função também existe. 366 | 367 | Um monóide bem simples é números e adição. 368 | 369 | 370 | ```js 371 | 1 + 1; // 2 372 | ``` 373 | 374 | O tipo do dado é número e a função é `+`, a adição dos dois números. 375 | 376 | ```js 377 | 1 + 0; // 1 378 | ``` 379 | 380 | O valor de identidade é `0`, adicionar `0` a qualquer número não vai alterá-lo. 381 | 382 | Para algo ser um monóide, também é necessário que o agrupamento das operações não afete o resultado. 383 | 384 | ```js 385 | 1 + (2 + 3) === (1 + 2) + 3; // true 386 | ``` 387 | 388 | Concatenação de arrays também pode ser chamado de monóide. 389 | 390 | ```js 391 | [1, 2].concat([3, 4]); // [1, 2, 3, 4] 392 | ``` 393 | 394 | O valor identidade é um array vazio `[]` 395 | 396 | ```js 397 | [1, 2].concat([]); // [1, 2] 398 | ``` 399 | 400 | Se identidade e funções de composições forem dados, as funções foram monóides por elas mesmas. 401 | 402 | ```js 403 | var identity = (a) => a; 404 | var compose = (f, g) => (x) => f(g(x)); 405 | 406 | compose(foo, identity) ≍ compose(identity, foo) ≍ foo 407 | ``` 408 | 409 | ## Monade 410 | 411 | Uma monade é um objeto com funções [`of`](#functor-apontado) e `chain`. `chain` é tipo [`map`](#functor), exceto pelo fato que "desninha" o objeto aninhado resultante. 412 | 413 | ```js 414 | ['cat,dog', 'fish,bird'].chain((a) => a.split(',')) // ['cat', 'dog', 'fish', 'bird'] 415 | 416 | // Em contraste ao map 417 | ['cat,dog', 'fish,bird'].map((a) => a.split(',')) // [['cat', 'dog'], ['fish', 'bird']] 418 | ``` 419 | 420 | `of` também é conhecido como `return` em outras linguagens funcionais. 421 | `chain` também é conhecido como `flatmap` e `bind` em outras linguagens. 422 | 423 | ## Comonade 424 | 425 | Um objeto que possui as funções `extract` e `extend`. 426 | 427 | ```js 428 | const CoIdentity = (v) => ({ 429 | val: v, 430 | extract() { return this.val }, 431 | extend(f) { return CoIdentity(f(this)) } 432 | }) 433 | ``` 434 | 435 | Extract tira um valor do functor. 436 | 437 | ```js 438 | CoIdentity(1).extract() // 1 439 | ``` 440 | 441 | Extend executa a função na comonade. A função deve retornar o mesmo tipo de comonade. 442 | 443 | ```js 444 | CoIdentity(1).extend((co) => co.extract() + 1) // CoIdentity(2) 445 | ``` 446 | 447 | ## Functor Aplicativo 448 | 449 | Um functor aplicativo é um objeto com uma função `ap`. `ap` aplica uma função no objeto a outro valor em outro objeto do mesmo tipo. 450 | 451 | ```js 452 | [(a) => a + 1].ap([1]) // [2] 453 | ``` 454 | 455 | ## Morfismo 456 | 457 | Uma função de transformação. 458 | 459 | ## Isomorfimos 460 | 461 | Um par de transformações entre 2 tipos de objetos que é estrutura por natureza e não há perda de dados. 462 | 463 | Exemplo, coordenadas 2D devem ser armazenadas em uma array `[2,3]` ou objeto `{x: 2, y: 3}`. 464 | 465 | ```js 466 | // Prover funções para converter em ambas as direções as faz isomórficas. 467 | const pairToCoords = (pair) => ({x: pair[0], y: pair[1]}) 468 | 469 | const coordsToPair = (coords) => [coords.x, coords.y] 470 | 471 | coordsToPair(pairToCoords([1, 2])) // [1, 2] 472 | 473 | pairToCoords(coordsToPair({x: 1, y: 2})) // {x: 1, y: 2} 474 | ``` 475 | 476 | 477 | 478 | ## Setóide 479 | 480 | Um objeto que tem uma função `equals` que pode ser usada para comparar outros objetos do mesmo tipo. 481 | 482 | Vamos transformar Array em setóide: 483 | 484 | ```js 485 | Array.prototype.equals = (arr) => { 486 | var len = this.length 487 | if (len != arr.length) { 488 | return false 489 | } 490 | for (var i = 0; i < len; i++) { 491 | if (this[i] !=== arr[i]) { 492 | return false 493 | } 494 | } 495 | return true 496 | } 497 | 498 | [1, 2].equals([1, 2]) // true 499 | [1, 2].equals([0]) // false 500 | ``` 501 | 502 | ## Semigrupo 503 | 504 | Um objeto que tem uma função `concat` que combina com outro objeto deo mesmo tipo. 505 | 506 | ```js 507 | [1].concat([2]) // [1, 2] 508 | ``` 509 | 510 | ## Dobrável 511 | 512 | Um objeto que possui uma função `reduce` que pode transformar o objeto em outro tipo. 513 | 514 | ```js 515 | let sum = (list) => list.reduce((acc, val) => acc + val, 0); 516 | sum([1, 2, 3]) // 6 517 | ``` 518 | 519 | ## Traversável 520 | 521 | TODO 522 | 523 | ## Assinaturas de Tipo 524 | 525 | Frequentemente, as funçẽos vão incluir comentário quy indicam os tipos dos seus argumentos e retornos. 526 | 527 | Há uma pequena variância na comunidade, mas geralmente seguem os seguintes padrões: 528 | 529 | ```js 530 | // nomeDaFunção :: tipoDoPrimeiroArgumento -> tipoDoSegundoArgumento -> tipoDoRetorno 531 | 532 | // add :: Number -> Number -> Number 533 | let add = (x) => (y) => x + y 534 | 535 | // increment :: Number -> Number 536 | let increment = (x) => x + 1 537 | ``` 538 | 539 | Se uma função aceita outra função como parâmetro, ela é envolva em parêntese. 540 | 541 | ```js 542 | // call :: (a -> b) -> a -> b 543 | let call = (f) => (x) => f(x) 544 | ``` 545 | 546 | As letras `a`, `b`, `c`, `d` são usadas para mostrar que o argumento pode ser de qualquer tipo. Nesse `map`, recebe uma função que transforma um valor do tipo `a` em outro do tipo `b`, ou um array de valores do tipo `a` e retorna um array de valores do tipo `b`. 547 | 548 | ```js 549 | // map :: (a -> b) -> [a] -> [b] 550 | let map = (f) => (list) => list.map(f) 551 | ``` 552 | 553 | ## Tipo de união 554 | Um tipo de união é a combinação de dois tipos em um terceiro. 555 | 556 | JS não tem tipos estáticos, mas vamos supor que queremos inventar um tipo `NumOrString`, que é a soma de um `String` e um `Number`. 557 | 558 | O operador `+` no JS funciona em strings e números, então podemos usar esse novo tipo para descrever suas entradas e saídas. 559 | 560 | ```js 561 | // add :: (NumOrString, NumOrString) -> NumOrString 562 | const add = (a, b) => a + b; 563 | 564 | add(1, 2); // Retorna número 3 565 | add('Foo', 2); // Retorna string "Foo2" 566 | add('Foo', 'Bar'); // Retorna string "FooBar" 567 | ``` 568 | 569 | Tipos de união também são conhecidos como tipos algebráicos, uniões marcadas, ou tipos de soma. 570 | 571 | Há [algumas](https://github.com/paldepind/union-type) [bibliotecas](https://github.com/puffnfresh/daggy) em JS que ajudam a definir e usar tipos de união. 572 | 573 | ## Tipo de produto 574 | 575 | Um tipo de **produto** combina tipos de uma forma que você provavelmente já está familiarizado. 576 | 577 | ```js 578 | // point :: (Number, Number) -> {x: Number, y: Number} 579 | const point = (x, y) => ({x: x, y: y}); 580 | ``` 581 | Isso é chamado de produto porque o total de valores possíveis da estrutura de dados ´e o produto dos valores diferentes. 582 | 583 | Veja também [Teoria dos conjuntos](https://en.wikipedia.org/wiki/Set_theory). 584 | 585 | ## Opção 586 | Opção é um [tipo de união](#tipo-de-uni%C3%A3o) com duas classes que geralmente são chamadas de `Some` (_alguma_) e `None` (_nenhuma_). 587 | 588 | Opção é útil para compor funções que podem não retornar um valor. 589 | 590 | ```js 591 | // Definição inocente 592 | 593 | const Some = (v) => ({ 594 | val: v, 595 | map(f) { 596 | return Some(f(this.val)); 597 | }, 598 | chain(f) { 599 | return f(this.val); 600 | } 601 | }); 602 | 603 | const None = () => ({ 604 | map(f){ 605 | return this; 606 | }, 607 | chain(f){ 608 | return this; 609 | } 610 | }); 611 | 612 | // maybeProp :: (String, {a}) -> Option a 613 | const maybeProp = (key, obj) => typeof obj[key] === 'undefined' ? None() : Some(obj[key]); 614 | ``` 615 | Use `chain` para colocar em sequência funções que retornam `Option`s 616 | ```js 617 | 618 | // getItem :: Cart -> Option CartItem 619 | const getItem = (cart) => maybeProp('item', cart); 620 | 621 | // getPrice :: Item -> Option Number 622 | const getPrice = (item) => maybeProp('price', item); 623 | 624 | // getNestedPrice :: cart -> Option a 625 | const getNestedPrice = (cart) => getItem(obj).chain(getPrice); 626 | 627 | getNestedPrice({}); // None() 628 | getNestedPrice({item: {foo: 1}}); // None() 629 | getNestedPrice({item: {price: 9.99}}); // Some(9.99) 630 | ``` 631 | 632 | `Option` também é conhecido como `Maybe` (_talvez_). `Some` às vezes é chamada de `Just` (_apenas_). `None` às vezes é chamada de `Nothing` (_nada_). 633 | 634 | --- 635 | 636 | __P.S:__ Sem as [contribuções maravilhosas](https://github.com/hemanth/functional-programming-jargon/graphs/contributors) esse repositório não teria sentido algum! 637 | --------------------------------------------------------------------------------