JS Funcional
1019 |Possuimos 2 grandes paradigmas de programação:
1020 |-
1021 |
- funcional 1022 |
- imperativo 1023 |
A Funcional é a mais antiga, sua primeira linguagem foi criada em 1955 (IPL) e posteriomente a mais popular LISP foi criada em 1958. Fortran e COBOL foram criadas respectivamentes em 1956 e 1959, são imperativas.
1025 |[Explicar como ira funcionar o curso]
1026 |O que é programação funcional?
1027 |Programação funcional é um paradigma de programação que trata a computação como uma avaliação de funções matemáticas e evita estados ou dados mutáveis. Utiliza a aplicação de funções, em contraste da programação imperativa, que enfatiza mudanças no estado do programa.
1028 |Uma função pode ter ou não ter parâmetros e um simples valor de retorno. Os parâmetros são os valores de entrada da função, e o valor de retorno é o resultado da função. A definição de uma função descreve como a função será avaliada em termos de outras funções.
1029 |Assim como na orientação a objetos a menor parte de um sistema é um objeto, você pode atribuir objetos a variáveis, pode passá-los por parâmetro e ter métodos retornando objetos, na programação funcional, a menor parte do seu sistema é uma função.
1030 |Por exemplo, a função f(x) = x^2 + 5 é definida utilizando funções de exponenciação e adição. Do mesmo modo, a linguagem deve oferecer funções básicas que não requerem definições adicionais.
1031 |[ESCREVER MAIS SOBRE]
1032 |Por que usar programação funcional?
1033 |Onde usar?
1034 |Quem está usando?
1035 |Linguagens funcionais
1036 |Hoje em dia com o aumento na necessidade de sistemas concorrentes as linguagens funcionais estão voltando para o mercado comercial. Vemos muito grandes empresas usares: Erlang, Haskell, Scala, etc.
1037 |Linguagens mais conhecidas:
1038 |-
1039 |
- Erlang 1040 |
- F# 1041 |
- Haskell 1042 |
- Lisp 1043 |
- OCaml 1044 |
- R 1045 |
- Scala 1046 |
- Scheme 1047 |
LISP introduziu a maioria das características hoje encontradas nas modernas linguagens de programação funcional. Scheme foi uma tentativa posterior de simplificar e melhorar LISP. Haskell foi lançada no fim dos anos 1980 numa tentativa de juntar muitas ideias na pesquisa de programação funcional.
1049 |Lambda
1050 |O cálculo lambda pode ser considerado a primeira linguagem de programação funcional, embora nunca tenha sido projetada para ser realmente executada em um computador. É um modelo de computação projetado por Alonzo Church nos anos 1930 que oferece um modo muito formal de descrever um cálculo de uma função.
1051 |A ideia de Church era usar a noção de “processo” ou “transformação” (função) como essencial para fundamentar a matemática, ao invés da noção de conjunto de Cantor. O lambda cálculo não deu muito certo para isso na época, mas acabou sendo importante em outra questão do tempo: a busca pela definição formal do que vem a ser um procedimento efetivo. Em termos atuais, diríamos que essa busca tentava definir formalmente o que é “computação”.
1052 |(A ideia de usar o conceito de transformação como central na matemática retornou na segunda metade do século XX através da Teoria das Categorias, mas isso é outra história.)
1053 |Notação
1054 |Essa notação pode parecer um pouco confusa no início, mas veremos que não é nenhum bicho de sete cabeças.
1055 |Queria ter colocado o Tiamat, mas ele tem 5 cabeças apenas :(
1057 |(λx.x) y
1058 |
1059 |
1060 | Basicamente (λx.x) tem como resultado a expressão y.
1061 |Onde (E = x, F = y), guardem bem essa informação E é o resultado onde x é substituído pela expressão[função?] F.
1062 |Agora se F (λx.x)(λx.y) tem como resultado (λx.y), então (E = x, F = (λx.y)). E é só isso, substituição textual.
1063 |A sintaxe das expressões-lambda é determinada por duas operações: abstração e aplicação (sendo que a aplicação envolve uma operação de substituição chamada conversão-β). Uma expressão-lambda pode ser uma variável, uma abstração de uma expressão, ou uma aplicação de duas expressões:
1064 |-
1065 |
- Variáveis: x, y, z, um conjunto qualquer de nomes de variáveis. 1066 |
- Abstrações: dada uma expressão-lambda E, podemos formar uma abstração de E usando λ + variável + ‘.’ + E. Por exemplo: λx.x 1067 |
- Aplicações: dadas duas expressões-lambda E e F, a expressão da aplicação é formada pela justaposição de uma ao lado da outra: E F 1068 |
A conversão-β é a regra de substituição que diz como a aplicação deve funcionar.
1070 |Analisemos essa expressão (λ x. + x 1) 4
a conversão-β é:
+ 4 1
1072 |
1073 |
1074 | Fácil não?
1075 |Zuerinha vou explicar é claro, vamos lá:
1077 |(λ x. + x 1) 4 → + 4 1
1078 | // (λ"variável"."E") "F"
1079 | // variável = x
1080 | // E = + x 1
1081 | // F = 4
1082 |
1083 |
1084 | Nesse caso a conversão-β resulta na expressão[?] + 4 1
onde substituímos a variável x
da função[?] E
pelo valor de F
, agora ficou fácil né?
[Falar mais]
1087 |Teoria das Categorias
1088 |A teoria das categorias é uma teoria matemática que trata de forma abstrata das estruturas matemáticas e dos relacionamentos entre elas. Ela pode ser entendida como um “jogo de setas”, em que se abstrai o significado das construções.
1089 |As aplicações da teoria das categorias estendem-se por áreas como álgebra, teoria da recursividade, semântica formal, etc.
1090 |Uma única operação exigida em uma categoria é a composição. Ouviremos falar muito disso ainda.
1091 |-
1092 |
- uma classe de objetos a, b, c, … 1093 |
- para cada par de objetos a,b, uma classe de morfismos ou setas de a para b, denotados por f:a -> b (e neste caso se diz que a é o objeto origem e b é o objeto destino da seta); 1094 |
- para cada objeto a, um morfismo chamado identidade em a, id_a:a\rightarrow a que tem origem e destino em a; 1095 |
- uma operação de composição que associa a cada par de morfismos. 1096 |
Functor
1099 |1100 |1102 |A functor is a function, given a value and a function, unwraps the values to get to its inner value(s), calls the given function with the inner value(s), wraps the returned values in a new structure, and returns the new structure.
1101 |
Vamos entender parte por parte:
1103 |-
1104 |
- functor é uma função que irá receber um valor e uma função 1105 |
- desembrulha? os valores para chegar a seu(s) valor(es) interno(s) 1106 |
- chama a função dada com o(s) valor(es) interno(s) 1107 |
- envolve os valores devolvidos em uma nova estrutura 1108 |
- e retorna a nova estrutura. 1109 |
Sim eu sei que é basicamente a tradução do texto acima, bom então vamos aqo que interessa, códigoooooooooooo:
1112 |function plus1(value) {
1113 | return value + 1
1114 | }
1115 |
1116 | function plus2(value) {
1117 | return value + 2
1118 | }
1119 |
1120 |
1121 | Criamos duas funções simples, plus1
adiciona 1 ao value
e plus2
adiciona 2, agora vamos escrever uma função ara que possamos usar qualquer uma dessas funções como e quando necessário:
function F(value, fn) {
1123 | return fn(value)
1124 | }
1125 |
1126 | F(1, plus1) // 2
1127 | ```js
1128 |
1129 | Essa função irá funcionar enquanto passarmos um inteiro, vamos tentar passar um *Array*:
1130 |
1131 | ```js
1132 | F([1, 2, 3], plus1) ==>> '1,2,31'
1133 |
1134 | Por exemplo a função `map` é um *functor*!
1135 |
1136 | No caso do Jasvascript, *filter* é um *functor* porque retorna um *Array*, entretando o *forEach* não é pois retorna *undefined*, ou seja, ele não mantém a estrutura.
1137 |
1138 | *Functors* são definidos como "[homomorfismos](https://pt.wikipedia.org/wiki/Homomorfismo) entre categorias", vamos entender melhor esse significado:
1139 |
1140 | - homo = mesmo, igual
1141 | - morfismos = funções que mantém estrutura
1142 | - categoria = tipo
1143 |
1144 | De acordo com a teoria, a função `F` é um *functor* quando as duas funções comuns combináveis f e g, como no exemplo abaixo:
1145 |
1146 |
1147 | F(f . g) = F(f) . F(g)
1148 |
1149 | Onde `.` indicam composição, ou seja, *functors* precisam preservar a composição.
1150 |
1151 | #####Array Functor
1152 |
1153 | Como disse que o `map` é um *functor* então vamos provar isso.
1154 |
1155 | ```js
1156 | function compose(f, g) {
1157 | return function(x) {return f(g(x))}
1158 | }
1159 |
1160 | Fazer composição de funções é criar uma chamada de um conjunto de funções, chamando a função seguinte, com resultados da função anterior. Note que a nossa função de composição acima funciona da direita para a esquerda. g é chamado pela primeira vez, em seguida, f.
1161 |[Quando mostrar a composição]
1162 | Isso lembra alguma coisa pra você? Bom logo logo verá um exemplo mais conhecido.
[ESCREVER MAIS SOBRE]
1164 |Por que JavaScript é funcional?
1165 |Funções
1166 |No JavaScript uma função nada mais é que um objeto que possui atributos como:
1167 |-
1168 |
- arguments 1169 |
- name 1170 |
- length 1171 |
E funções importantes como:
1173 |-
1174 |
- apply 1175 |
- call 1176 |
Para criarmos uma funçõa no JavaScript é muito simples, precisamos apenas utilizar a palavra ´function´:
1178 |function add(a, b) {
1180 | return a + b;
1181 | };
1182 |
1183 |
1184 | Podemos usar um exemplo mais simples ainda, uma função que duplica Strings:
1185 |var repeat = function(s) {
1186 | return s + s;
1187 | };
1188 |
1189 | repeat('Na');
1190 | // NaNA
1191 |
1192 |
1193 | Então se chamamos apenas a função repeat
dessa forma, teremos um resultado indesejado.
Sim meu caro aluno, prete atenção no exemplo abaixo:
1196 |repeat(2);
1197 | // 4
1198 |
1199 |
1200 | Aí encontramos o problema!
1201 |Nesse caso ele não está mais repetindo a String como desejado inicialmente, agora ela está multiplicando o valor por 2 caso seja um Number. Isso porque não temos um contrato com uma função que retorne apenas Strings. Para resolver esse problema é fácil, criamos essa função abaixo:
1202 |var str = function(s) {
1203 | if(typeof s !== 'string') {
1204 | throw new TypeError('Expected a string');
1205 | }
1206 | else {
1207 | return s;
1208 | }
1209 | }
1210 |
1211 |
1212 | Agora você passa uma String para a função, como valor de entrada, e espera-se que seu retorno também seja uma String, como valor de saída.
1213 |Refatorando nossa função repeat
:
var repeat = function(s) {
1215 | var s = str(s)
1216 | return s + s;
1217 | };
1218 |
1219 | repeat('Na');
1220 | // NaNA
1221 | repeat(1)
1222 | // TypeError: Expected a string
1223 |
1224 |
1225 | [EXPLICAR MAIS]
1226 |First-class citizens
1227 |No JavaScript a função é first-class citizen, assim como objeto, entidade ou valor, porque ela suporta todas as operações comuns às outras entidades.
1228 |Essas operações incluem:
1230 |-
1231 |
- assinada a uma variável 1232 |
- retornada de uma função 1233 |
- ser passada por parâmetro 1234 |
Vamos mostrar cada uma dessas operações com o exemplo anterior:
1236 |// assinada a uma variável
1237 | var add = function (a, b) {
1238 | return a + b;
1239 | }
1240 |
1241 | add(400, 20); // 420
1242 |
1243 |
1244 | // retornada de uma função
1245 | function adder(a) {
1246 | return function(b) {
1247 | return a + b;
1248 | }
1249 | }
1250 |
1251 | var _add = adder(20);
1252 | _add(400) // 420
1253 | _add(646) // 666
1254 |
1255 |
1256 | Podemos melhorar esse exemplo e criarmos a função de multiplicar.
1257 |// retornada de uma função
1258 | function multiply(a) {
1259 | var sum = 0;
1260 | return function(b) {
1261 | sum = b;
1262 | for(i=1; i<a; i++){
1263 | sum += b;
1264 | }
1265 | return sum;
1266 | };
1267 | }
1268 |
1269 | multiply(2)(333); //666
1270 |
1271 |
1272 | Você deve ter percebido que podemos utilizar 2 formas de passagem de parâmetros, correto?
1273 |Vamos entender melhor como isso funciona, vamos analisar o exemplo coma soma por sem mais simples, porém desta vez vendo os valores dos parâmetros.
1274 |// retornada de uma função
1275 | function adder(a) {
1276 | console.log('a', a);
1277 | return function(b) {
1278 | console.log('b', b);
1279 | return a + b;
1280 | }
1281 | }
1282 |
1283 | var _add = adder(20);
1284 | _add(400) // 420
1285 | _add(646) // 666
1286 |
1287 |
1288 | Na linha:
1289 |var _add = adder(20);
1290 | // a 20
1291 |
1292 |
1293 | Basicamente a função está apenas instanciando o valor de a
e retornando a função com a soma já usando o a
, falaremos mais disso posteriormente, logo _add
não recebe o valor de a
, mas sim a funçao da soma:
function adder(a) {
1295 | var a = a; // 20
1296 | return function(b) {
1297 | return a + b;
1298 | }
1299 | }
1300 |
1301 |
1302 | Depois quando chamamos a função _add
passando 400
como parâmetro
1303 |
_add(400)
1304 | // b 420
1305 | // 440
1306 |
1307 | Estamos passando o 400
para a função que recebe b
desse jeito retornando o valor da nossa soma:
function(b) { //400
1309 | return a + b; //420
1310 | }
1311 |
1312 |
1313 | Para entender melhor como isso acontece falarei mais adiante sobre closures.
1314 |High-order function
1315 |-
1316 |
- recebe uma ou mais funções como parâmetro 1317 |
- retorna uma função 1318 |