Introdução à programação
funcional
GABRIEL SCHADE CARDOSO
Quem é esse tal de Gabriel?
 Bacharel em ciência da computação
 Mestre em computação aplicada
 Microsoft Innovative Educator (MIE)
 Microsoft Specialist (MS)
 C#
 Javascript
 ASP .NET MVC
3
GUI
Sobre mim
 Microsoft Certified Solutions Assiciate (MCSA)
 Web Applications
 Autor dos livros da editora casa do código sobre
os assuntos:
 Kinect
 Windows Phone
 Programação Funcional
4
GUI
Sobre mim
 Desenvolvedor Senior
 Professor
 Revisor
5
GUI
Sobre mim
O que é programação
funcional?
Programação Funcional
 Programação funcional é um paradigma de
programação.
 Enfatiza o uso de funções e evita mudanças de
estados ou dados mutáveis.
Programação Funcional
 O maior complicador sobre o paradigma
funcional é que ele é mais complicado.
 Mentira, não é, mas as pessoas geralmente se
assustam com ele.
Programação Funcional
 Só precisamos aprender:
1. Funtores;
2. Funtores Aplicativos;
3. Currying;
4. Aplicação Parcial;
5. Monads;
6. Monoids;
7. ...
 Mas já precisamos aprender:
1. Interfaces;
2. Polimorfismo;
3. Herança;
4. Encapsulamento;
5. Generics;
6. SOLID;
7. ...
Programação Funcional
 Por que achamos normal aprender os
significados das palavras difíceis do lado direito e
acham super difícil aprender o significado das
palavras da esquerda?
Programação Funcional
 Porque quando migramos de uma linguagem
para outra, estamos acostumados com algumas
keywords e conceitos já aprendidos.
Programação Funcional
 Isso porque todas as linguagens imperativas
usam a mesma maneira de pensar, então tudo
que aprendemos em uma linguagem pode ser
transferido para a outra.
 Do Portugol para o C++, para o Java, para o C#
e assim por diante.
Programação Funcional
 As linguagens funcionais são criadas para
funcionar com outra forma de pensar.
 Isso é bastante difícil.
 Então para a aula de hoje, tente esquecer boa
parte dos conceitos já consolidados em sua
cabeça. Vamos começar de novo, beleza?
Programação Funcional
 Em programação funcional não há:
 Variáveis
 Laços de repetição
 Objetos
Programação Funcional
 Ok, em F# existem estas coisas, mas não
vamos usá-las.
Vincular ao invés de
atribuir
Bind > Assignment
 Em linguagens imperativas é comum
atribuirmos valores à variáveis;
 Em linguagens funcionais nós vinculamos um
valor à um identificador.
Bind > Assignment
 Não declaramos o tipo!
Bind > Assignment
 Mas é fortemente tipado!
Bind > Assignment
 Mas qual a diferença entre isso e uma variável?
Bind > Assignment
 Chamamos isso de valor simples.
 Estes valores podem ser de qualquer tipo:
São fortemente tipados
Bind > Assignment
 Um valor pode ser atribuído a mais de um
identificador:
 Agora tanto o identificador nome quando o
identificador meuNome estão vinculados à string
“Gabriel”
Bind > Assignment
 Podemos fazer o mesmo com listas e arrays:
Bind > Assignment
 Para acessar um elemento em uma lista ou
array, utilize o nome do identificador seguido de
.[posição]:
Bind > Assignment
 Além dos valores simples, há outro tipo de valor
muito importante;
 São os chamados, valores de função.
Funções
 Da mesma forma que podemos vincular um
valor à um identificador, podemos vincular uma
função a um identificador.
Funções
 Vamos pensar um pouco sobre esta função.
1. Não declaramos que ela é uma função
2. Não declaramos o tipo do parâmetro e nem do retorno
3. Não explicitamos o valor que esta função retorna (return)
Funções
 Respostas:
1. Sempre que houver parâmetros, é uma função
2. Os tipos são inferidos, mas é possível determiná-los
3. O retorno da função sempre será o resultado de sua última
linha
Funções
1. Caso não houver parâmetro, como explicito que é uma
função e não um valor simples?
2. Como determino os tipos?
Funções
 As funções também tem tipo, sempre o tipo de
uma função é definido por:
 parâmetro -> retorno
Funções
 Os escopos são delimitados por espaçamento,
então para criar funções com mais de uma linha,
é necessário usar o tab:
Funções
 Os valores de funções se comportam de forma
parecida com os valores simples. Incluindo a
possibilidade de adicionar mais de um
identificador:
Funções
 As funções também podem utilizar a notação
que chamamos de anônima, ou seja, na
declaração da função, não colocamos um nome
à ela.
Funções
 Na notação para funções anônimas também é
necessário utilizar a palavra reservada fun e o
operador -> para dividir os parâmetros da
função.
 Esta notação é utilizada para passagem de
parâmetro e para funções curtas ou de contextos
específicos.
Praticar um pouco
Prática
 Vamos criar um novo projeto do tipo Console:
Prática
Prática
 Função main inicial:
Prática
 Função main inicial:
Prática
 Função main inicial:
Prática
Prática
1. Crie um valor que esteja vinculado à seu nome e
sua idade, depois escreva-os no console;
2. Crie um array contendo 3 notas (float) e exiba a
média dos três valores no console.
3. Crie uma função que receba um nome e uma idade
e escreva-os no console;
4. Crie uma função que some um número com 10;
Soluções
Currying
Currying
 Toda a ideia da programação funcional se
baseia no calculo lambda e em funções
matemáticas.
 As funções matemáticas possuem uma
propriedade bastante específica: 1 entrada – 1
saída.
Currying
 Se todas as funções só podem ter 1 entrada
(parâmetro) e 1 retorno, como uma função
poderá conter 2 parâmetros?
Currying
 Toda função que possui múltiplos parâmetros é
reescrita como uma série de funções, cada uma
contendo apenas um parâmetro.
 Este processo é feito automaticamente pelo
compilador.
Currying
 Este processo se chama Currying devido ao
matemático Haskell Curry.
Currying
 Este processo se chama Currying devido ao
matemático Haskell Curry.
Currying
 Vamos relembrar os tipos dos valores de
função:
 parâmetro -> retorno
Currying
 O que acontece se a função tiver 2 parâmetros?
Currying
 Mas como usamos esta função?
 Usamos da mesma forma que as funções
normais...
 Mas então, o que afinal é o currying?
Currying
 Vamos analisar melhor:
 Esta função recebe um int e retorna um
(int -> int), ou seja, uma função que recebe um
int e retorna um outro int.
Currying
 Ao utilizarmos a função desta forma:
 O compilador nos ajuda para tornar as coisas
transparentes, mas é como se tivéssemos feito
isso:
Currying
 Então, mesmo uma função de 2 parâmetros
pode ser chamada passando apenas 1?
 Sim
 E o retorno dela será outra função, que não
possui nome, mas que pode ser vinculada à um
identificador.
Currying
Currying
 Através do Currying é possível gerarmos novas
funções a partir de funções existentes:
Currying -> Aplicação Parcial
 Quando invocamos uma função informando
apenas parte dos parâmetros estamos realizando
uma aplicação parcial:
Prática
1. Crie uma função que receba duas strings
(saudação e nome) e exiba-as concatenadas no
console;
2. A partir da função criada, utilize currying e aplicação
parcial para criar as funções Ola e Tchau, que
devem esperar apenas um nome por parâmetro e
exibir no console respectivamente:
- Olá fulano
- Tchau fulano
Soluções
Funções de alta ordem
Funções de Alta ordem
 Toda função que recebe uma função por
parâmetro, ou retorna uma função é chamada de
função de alta ordem (HOF).
 Toda função em F# com mais de um parâmetro
em F# é uma função de alta ordem.
Funções de Alta ordem
 Estas funções são muito utilizadas em
diferentes escopos e linguagens.
 Java, C#, F#, OCaml, C++, JavaScript ...
 Geralmente uma função de alta ordem torna o
código mais genérico e reutilizável
Funções de Alta ordem
 Toda função que recebe uma função por
parâmetro, ou retorna uma função é chamada de
função de alta ordem (HOF).
 Toda função em F# com mais de um parâmetro
em F# é uma função de alta ordem.
Funções de Alta ordem
 Existem três funções de alta ordem muito
populares: filter, map e reduce.
 Estas três funções são utilizadas para alterar
listas/arrays.
Funções de Alta ordem
 Primeiro vamos ver a função filter
 Esta função é utilizada para filtrar as listas
baseando-se em uma condição que será testada
em cada um dos elementos.
Funções de Alta ordem
 Vamos analisar:
 Para o caso do filter, a função informada no parâmetro precisa retornar
um bool;
 Esta função será aplicada em cada um dos elementos;
 O retorno será uma lista contendo os elementos onde a função
retornou true -> [0 ; 2]
Funções de Alta ordem
 Diferente do filter, a função map sempre
devolve uma lista de mesmo tamanho. Ela é
utilizada para transformar os dados.
O retorno será -> [0 ; 2 ; 4 ; 6]
Funções de Alta ordem
 Esta função também pode ser utilizada para
transformar o dado de um tipo em outro tipo, veja
este exemplo:
Funções de Alta ordem
 Vamos analisar:
 Estamos passando por parâmetro a mesma função anônima
que utilizamos na HOF filter.
 Desta vez o retorno será: [true, false, true, false]
Funções de Alta ordem
 O reduce é um pouco diferente das demais,
neste caso, reduzimos toda a lista para um único
valor.
 Além disso, esta função utiliza acumuladores,
então a função anônima do parâmetro recebe
dois valores (acumulador + elemento)
Funções de Alta ordem
 Neste caso, estamos somando todos os
elementos da lista.
 Retorno -> 6 (0 + 1 + 2 + 3)
Funções de Alta ordem
 Informações importantes!
 As funções informadas no parâmetro não
precisam ser funções anônimas, basta ser do
mesmo tipo esperado.
Prática
1. Crie uma função que receba uma lista de inteiros e retorne
esta mesma lista contendo os valores elevados ao
quadrado
2. Crie uma função que receba dois parâmetros: uma lista de
strings e uma outra string. Esta função deve retornar todos
os elementos da lista onde o começo do texto seja igual à
a string informada no segundo parâmetro. (Utilize a função
StartsWith)
Prática
3. Crie uma função que receba uma lista de inteiros e retorne
o produto de toda a lista (multiplique todos os elementos
com o reduce).
Soluções
Pipeline
Pipeline
 O operador de pipeline é bastante popular nas
linguagens de programação, seu símbolo pode
alterar de acordo com a linguagem, mas em F#
definimos como:
 Pipeline: |>
Pipeline
 Em programação funcional os operadores
também são definidos por funções, veja a função
do operador pipeline (|>):
Pipeline
 Tudo que este operador faz é alterar a ordem de
chamada da função e de seu parâmetro, pode
soar inútil, mas para organização de código, é
excelente.
Pipeline
 Veja esta função, ela utilizará o filter e o map.
Pipeline
 Primeiro inicializamos a lista com valores de 1
até 10.
 Depois obtemos todos os valores menores do
que cinco.
 Por fim realizamos a multiplicação.
Pipeline
 Para conseguir fazer isso, precisamos criar
vários valores intermediários. Pois teríamos que
informar a listagem para a próxima função.
 Utilizando o pipeline a função se torna mais
legível e menor. Veja:
Pipeline
 Antes:
Pipeline
 Depois:
Pipeline
 Também é comum utilizar o operador pipeline
para inverter um valor boolean, através da
função not
Prática
1. Crie uma função que receba uma lista de inteiros,
multiplique todos os elementos por 2, depois multiplique
por 3. Após isso, filtre a lista para obter apenas os valores
maiores que 30 e retorne a soma de todos eles.
2. Crie uma função que receba dois números inteiros, some-
os, depois multiplique o resultado por 5 e retorne se o
número é par ou impar.
Soluções
Me encontre em
/gabrielschade
/gabrielschade
/gabrielschade
/gabrielschade
https://gabrielschade.github.io
Perguntas?

Introdução à programação funcional

  • 1.
  • 2.
    Quem é essetal de Gabriel?
  • 3.
     Bacharel emciência da computação  Mestre em computação aplicada  Microsoft Innovative Educator (MIE)  Microsoft Specialist (MS)  C#  Javascript  ASP .NET MVC 3 GUI Sobre mim
  • 4.
     Microsoft CertifiedSolutions Assiciate (MCSA)  Web Applications  Autor dos livros da editora casa do código sobre os assuntos:  Kinect  Windows Phone  Programação Funcional 4 GUI Sobre mim
  • 5.
     Desenvolvedor Senior Professor  Revisor 5 GUI Sobre mim
  • 6.
    O que éprogramação funcional?
  • 7.
    Programação Funcional  Programaçãofuncional é um paradigma de programação.  Enfatiza o uso de funções e evita mudanças de estados ou dados mutáveis.
  • 8.
    Programação Funcional  Omaior complicador sobre o paradigma funcional é que ele é mais complicado.  Mentira, não é, mas as pessoas geralmente se assustam com ele.
  • 9.
    Programação Funcional  Sóprecisamos aprender: 1. Funtores; 2. Funtores Aplicativos; 3. Currying; 4. Aplicação Parcial; 5. Monads; 6. Monoids; 7. ...  Mas já precisamos aprender: 1. Interfaces; 2. Polimorfismo; 3. Herança; 4. Encapsulamento; 5. Generics; 6. SOLID; 7. ...
  • 10.
    Programação Funcional  Porque achamos normal aprender os significados das palavras difíceis do lado direito e acham super difícil aprender o significado das palavras da esquerda?
  • 11.
    Programação Funcional  Porquequando migramos de uma linguagem para outra, estamos acostumados com algumas keywords e conceitos já aprendidos.
  • 12.
    Programação Funcional  Issoporque todas as linguagens imperativas usam a mesma maneira de pensar, então tudo que aprendemos em uma linguagem pode ser transferido para a outra.  Do Portugol para o C++, para o Java, para o C# e assim por diante.
  • 13.
    Programação Funcional  Aslinguagens funcionais são criadas para funcionar com outra forma de pensar.  Isso é bastante difícil.  Então para a aula de hoje, tente esquecer boa parte dos conceitos já consolidados em sua cabeça. Vamos começar de novo, beleza?
  • 14.
    Programação Funcional  Emprogramação funcional não há:  Variáveis  Laços de repetição  Objetos
  • 15.
    Programação Funcional  Ok,em F# existem estas coisas, mas não vamos usá-las.
  • 16.
    Vincular ao invésde atribuir
  • 17.
    Bind > Assignment Em linguagens imperativas é comum atribuirmos valores à variáveis;  Em linguagens funcionais nós vinculamos um valor à um identificador.
  • 18.
    Bind > Assignment Não declaramos o tipo!
  • 19.
    Bind > Assignment Mas é fortemente tipado!
  • 20.
    Bind > Assignment Mas qual a diferença entre isso e uma variável?
  • 21.
    Bind > Assignment Chamamos isso de valor simples.  Estes valores podem ser de qualquer tipo: São fortemente tipados
  • 22.
    Bind > Assignment Um valor pode ser atribuído a mais de um identificador:  Agora tanto o identificador nome quando o identificador meuNome estão vinculados à string “Gabriel”
  • 23.
    Bind > Assignment Podemos fazer o mesmo com listas e arrays:
  • 24.
    Bind > Assignment Para acessar um elemento em uma lista ou array, utilize o nome do identificador seguido de .[posição]:
  • 25.
    Bind > Assignment Além dos valores simples, há outro tipo de valor muito importante;  São os chamados, valores de função.
  • 26.
    Funções  Da mesmaforma que podemos vincular um valor à um identificador, podemos vincular uma função a um identificador.
  • 27.
    Funções  Vamos pensarum pouco sobre esta função. 1. Não declaramos que ela é uma função 2. Não declaramos o tipo do parâmetro e nem do retorno 3. Não explicitamos o valor que esta função retorna (return)
  • 28.
    Funções  Respostas: 1. Sempreque houver parâmetros, é uma função 2. Os tipos são inferidos, mas é possível determiná-los 3. O retorno da função sempre será o resultado de sua última linha
  • 29.
    Funções 1. Caso nãohouver parâmetro, como explicito que é uma função e não um valor simples? 2. Como determino os tipos?
  • 30.
    Funções  As funçõestambém tem tipo, sempre o tipo de uma função é definido por:  parâmetro -> retorno
  • 31.
    Funções  Os escopossão delimitados por espaçamento, então para criar funções com mais de uma linha, é necessário usar o tab:
  • 32.
    Funções  Os valoresde funções se comportam de forma parecida com os valores simples. Incluindo a possibilidade de adicionar mais de um identificador:
  • 33.
    Funções  As funçõestambém podem utilizar a notação que chamamos de anônima, ou seja, na declaração da função, não colocamos um nome à ela.
  • 34.
    Funções  Na notaçãopara funções anônimas também é necessário utilizar a palavra reservada fun e o operador -> para dividir os parâmetros da função.  Esta notação é utilizada para passagem de parâmetro e para funções curtas ou de contextos específicos.
  • 35.
  • 36.
    Prática  Vamos criarum novo projeto do tipo Console:
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
    Prática 1. Crie umvalor que esteja vinculado à seu nome e sua idade, depois escreva-os no console; 2. Crie um array contendo 3 notas (float) e exiba a média dos três valores no console. 3. Crie uma função que receba um nome e uma idade e escreva-os no console; 4. Crie uma função que some um número com 10;
  • 43.
  • 44.
  • 45.
    Currying  Toda aideia da programação funcional se baseia no calculo lambda e em funções matemáticas.  As funções matemáticas possuem uma propriedade bastante específica: 1 entrada – 1 saída.
  • 46.
    Currying  Se todasas funções só podem ter 1 entrada (parâmetro) e 1 retorno, como uma função poderá conter 2 parâmetros?
  • 47.
    Currying  Toda funçãoque possui múltiplos parâmetros é reescrita como uma série de funções, cada uma contendo apenas um parâmetro.  Este processo é feito automaticamente pelo compilador.
  • 48.
    Currying  Este processose chama Currying devido ao matemático Haskell Curry.
  • 49.
    Currying  Este processose chama Currying devido ao matemático Haskell Curry.
  • 50.
    Currying  Vamos relembraros tipos dos valores de função:  parâmetro -> retorno
  • 51.
    Currying  O queacontece se a função tiver 2 parâmetros?
  • 52.
    Currying  Mas comousamos esta função?  Usamos da mesma forma que as funções normais...  Mas então, o que afinal é o currying?
  • 53.
    Currying  Vamos analisarmelhor:  Esta função recebe um int e retorna um (int -> int), ou seja, uma função que recebe um int e retorna um outro int.
  • 54.
    Currying  Ao utilizarmosa função desta forma:  O compilador nos ajuda para tornar as coisas transparentes, mas é como se tivéssemos feito isso:
  • 55.
    Currying  Então, mesmouma função de 2 parâmetros pode ser chamada passando apenas 1?  Sim  E o retorno dela será outra função, que não possui nome, mas que pode ser vinculada à um identificador.
  • 56.
  • 57.
    Currying  Através doCurrying é possível gerarmos novas funções a partir de funções existentes:
  • 58.
    Currying -> AplicaçãoParcial  Quando invocamos uma função informando apenas parte dos parâmetros estamos realizando uma aplicação parcial:
  • 59.
    Prática 1. Crie umafunção que receba duas strings (saudação e nome) e exiba-as concatenadas no console; 2. A partir da função criada, utilize currying e aplicação parcial para criar as funções Ola e Tchau, que devem esperar apenas um nome por parâmetro e exibir no console respectivamente: - Olá fulano - Tchau fulano
  • 60.
  • 61.
  • 62.
    Funções de Altaordem  Toda função que recebe uma função por parâmetro, ou retorna uma função é chamada de função de alta ordem (HOF).  Toda função em F# com mais de um parâmetro em F# é uma função de alta ordem.
  • 63.
    Funções de Altaordem  Estas funções são muito utilizadas em diferentes escopos e linguagens.  Java, C#, F#, OCaml, C++, JavaScript ...  Geralmente uma função de alta ordem torna o código mais genérico e reutilizável
  • 64.
    Funções de Altaordem  Toda função que recebe uma função por parâmetro, ou retorna uma função é chamada de função de alta ordem (HOF).  Toda função em F# com mais de um parâmetro em F# é uma função de alta ordem.
  • 65.
    Funções de Altaordem  Existem três funções de alta ordem muito populares: filter, map e reduce.  Estas três funções são utilizadas para alterar listas/arrays.
  • 66.
    Funções de Altaordem  Primeiro vamos ver a função filter  Esta função é utilizada para filtrar as listas baseando-se em uma condição que será testada em cada um dos elementos.
  • 67.
    Funções de Altaordem  Vamos analisar:  Para o caso do filter, a função informada no parâmetro precisa retornar um bool;  Esta função será aplicada em cada um dos elementos;  O retorno será uma lista contendo os elementos onde a função retornou true -> [0 ; 2]
  • 68.
    Funções de Altaordem  Diferente do filter, a função map sempre devolve uma lista de mesmo tamanho. Ela é utilizada para transformar os dados. O retorno será -> [0 ; 2 ; 4 ; 6]
  • 69.
    Funções de Altaordem  Esta função também pode ser utilizada para transformar o dado de um tipo em outro tipo, veja este exemplo:
  • 70.
    Funções de Altaordem  Vamos analisar:  Estamos passando por parâmetro a mesma função anônima que utilizamos na HOF filter.  Desta vez o retorno será: [true, false, true, false]
  • 71.
    Funções de Altaordem  O reduce é um pouco diferente das demais, neste caso, reduzimos toda a lista para um único valor.  Além disso, esta função utiliza acumuladores, então a função anônima do parâmetro recebe dois valores (acumulador + elemento)
  • 72.
    Funções de Altaordem  Neste caso, estamos somando todos os elementos da lista.  Retorno -> 6 (0 + 1 + 2 + 3)
  • 73.
    Funções de Altaordem  Informações importantes!  As funções informadas no parâmetro não precisam ser funções anônimas, basta ser do mesmo tipo esperado.
  • 74.
    Prática 1. Crie umafunção que receba uma lista de inteiros e retorne esta mesma lista contendo os valores elevados ao quadrado 2. Crie uma função que receba dois parâmetros: uma lista de strings e uma outra string. Esta função deve retornar todos os elementos da lista onde o começo do texto seja igual à a string informada no segundo parâmetro. (Utilize a função StartsWith)
  • 75.
    Prática 3. Crie umafunção que receba uma lista de inteiros e retorne o produto de toda a lista (multiplique todos os elementos com o reduce).
  • 76.
  • 77.
  • 78.
    Pipeline  O operadorde pipeline é bastante popular nas linguagens de programação, seu símbolo pode alterar de acordo com a linguagem, mas em F# definimos como:  Pipeline: |>
  • 79.
    Pipeline  Em programaçãofuncional os operadores também são definidos por funções, veja a função do operador pipeline (|>):
  • 80.
    Pipeline  Tudo queeste operador faz é alterar a ordem de chamada da função e de seu parâmetro, pode soar inútil, mas para organização de código, é excelente.
  • 81.
    Pipeline  Veja estafunção, ela utilizará o filter e o map.
  • 82.
    Pipeline  Primeiro inicializamosa lista com valores de 1 até 10.  Depois obtemos todos os valores menores do que cinco.  Por fim realizamos a multiplicação.
  • 83.
    Pipeline  Para conseguirfazer isso, precisamos criar vários valores intermediários. Pois teríamos que informar a listagem para a próxima função.  Utilizando o pipeline a função se torna mais legível e menor. Veja:
  • 84.
  • 85.
  • 86.
    Pipeline  Também écomum utilizar o operador pipeline para inverter um valor boolean, através da função not
  • 87.
    Prática 1. Crie umafunção que receba uma lista de inteiros, multiplique todos os elementos por 2, depois multiplique por 3. Após isso, filtre a lista para obter apenas os valores maiores que 30 e retorne a soma de todos eles. 2. Crie uma função que receba dois números inteiros, some- os, depois multiplique o resultado por 5 e retorne se o número é par ou impar.
  • 88.
  • 89.
  • 90.