Você está na página 1de 94

Paradigma Funcional

Eduardo Feitosa
efeitosa@icomp.ufam.edu.br
Material de Referência
● SEBESTA. "Conceitos de Linguagens de
Programação"
○ Capítulo 7: "Expressões e Sentenças de Atribuição"
■ Em particular, Seção 7.2.2 e subseções
● Ordem de avaliação dos operandos
● Efeitos colaterais
● Transparência referencial

● Capítulo 15: "Linguagens de Programação Funcional"


Funcional vs Imperativo
Paradigmas Imperativos
● Qual a “maneira de pensar” no paradigma
procedimental?
○ Como “desenhar” um padrão de triângulos?
Paradigmas Imperativos
● Qual a “maneira de pensar” no paradigma
procedimental?
○ Como “desenhar” um padrão de triângulos?

*
Paradigmas Imperativos
● Qual a “maneira de pensar” no paradigma
procedimental?
○ Como “desenhar” um padrão de triângulos?

*
**
Paradigmas Imperativos
● Qual a “maneira de pensar” no paradigma
procedimental?
○ Como “desenhar” um padrão de triângulos?

*
**
***
Paradigmas Imperativos
● Qual a “maneira de pensar” no paradigma
procedimental?
○ Como “desenhar” um padrão de triângulos?

*
**
***
****
Paradigmas Imperativos
● Qual a “maneira de pensar” no paradigma
procedimental?
○ Como “desenhar” um padrão de triângulos?

*
**
***
****
*****
Paradigmas Imperativos
● Qual a “maneira de pensar” no paradigma
procedimental?
○ Como “desenhar” um padrão de triângulos?

*
**
***
****
*****
******
Paradigma Imperativo
● O projeto das linguagens imperativas é baseado na
arquitetura de von Neumann
○ Eficiência é a preocupação primária, ao invés da
adequação da linguagem para o desenvolvimento de
software.

● As linguagens imperativas podem ser vistas como


uma sucessão de melhorias ao modelo básico
(Fortran 1).
Paradigma Funcional
● O projeto das linguagens funcionais é baseado em
funções matemáticas
○ Uma base teórica sólida
○ Sem preocupação com a arquitetura da máquina

● Interesse cresceu após Backus falar ao receber o


ACM Turing Award em 1977
○ Os programas escritos em linguagens de programação
puramente funcionais são mais legíveis, mais confiáveis, e
tem mais chances de estarem corretos
○ O significado das expressões são independentes do
contexto
Paradigma Funcional
● O paradigma funcional tem como base
○ Funções matemáticas
○ Cálculo lambda

● Características
○ Programas são coleções de funções e de aplicações
dessas funções (chamadas)
○ Algoritmos descrevem o quê o programa deve realizar,
não como
○ Não existe estado
Funções Matemáticas
● A ordem de avaliação das expressões de uma função
é controlada por recursão e por expressões
condicionais

● Não é controlada pela sequência ou pela repetição


interativa (comum nas linguagens imperativas)

● Uma função matemática sempre define o mesmo


valor, para os mesmos argumentos
Funções Matemáticas
● Funções simples
○ Definição de função: 𝑐𝑢𝑏𝑜 𝑥 = 𝑥 ∗ 𝑥 ∗ 𝑥
○ Aplicação de função: cubo(8)

● As vezes é conveniente separar a atividade de definir


uma função e a atividade de nomear uma função
○ Notação lambda (Alonzo Church 1941)
Funções Matemáticas
● Formas funcionais
○ Uma função de alta ordem, ou forma funcional, é aquela
que toma funções como parâmetro, produz uma função
como resultado, ou ambos

● Composição de funções
○ Toma duas funções como parâmetro e define uma função
cujo o valor é a primeira função aplicada ao resultado da
segunda
○ h ≡ 𝑓 ∘ 𝑔, h(x) ≡ 𝑓(𝑔(𝑥))
Funções Matemáticas
● Aplicar a tudo (Apply to all)
○ Toma uma função como parâmetro e resulta em
uma lista de valores aplicando a função dada a
cada elemento da lista de parâmetros

● Forma: 𝛼
○ h(𝑥) ≡ 𝑥 ∗ 𝑥
○ α(h, (2, 3, 4)) 𝑟𝑒𝑠𝑢𝑙𝑡𝑎 (4, 9, 16)
Fundamentos das Linguagens
Funcionais
● O objetivo do projeto LPF é imitar funções
matemáticas no maior grau possível

●O processo básico de computação é


fundamentalmente diferente entre LPF e linguagens
imperativas

● Em uma LPF, variáveis não são necessárias, como é


o caso na matemática
Fundamentos das Linguagens
Funcionais
● Uma LPF deve prover
○ Um conjunto de funções primitivas
○ Um conjunto de formas funcionais
○ Um operador de aplicação de função
○ e algumas estruturas para representar dados

● Em geral, são implementadas com interpretadores,


mas elas também podem ser compiladas
○ As linguagens imperativas em geral oferecem suporte
limitado a programação funcional
Fundamentos das Linguagens
Funcionais
● Numa linguagem funcional, tudo, até mesmo o
próprio programa, é uma função
● Quando falamos função, pensamos no conceito
matemático deste termo:
f(a, b, …) : Dom → CDom
○ Uma função f mapeia valores de Dom em Cdom
○ f pode mapear cada valor de Dom a, no máximo, 1 único
valor de CDom
○ Se aplicamos f seguidamente para os mesmos valores de
entrada (valores para a, b, …), obtemos sempre o mesmo
valor resultante
Fundamentos das Linguagens
Funcionais
● Pelo fato de tudo ser função, algumas características
interessantes no uso de funções são facilmente
descritas nestas linguagens:
○ Passagem de funções por parâmetro
○ Retorno de funções por outras funções
○ Composição de funções
○ Funções anônimas
Paradigma Funcional
● Fatorial imperativo vs. funcional

def fatorial(n): Mudança de estado


f=1
for i in range(1, n + 1): Iteração e sequência
f *= i
return f

def fatorial(n): Não há variáveis (sem estado)


if n <= 1:
return 1 Recursão
else:
return n * fatorial(n - 1)
Paradigma Funcional
● Pontos positivos da programação funcional
○ Mais abstrata (alto nível)
○ Soluções mais modulares
○ Fácil de testar e depurar
○ Não propensa a efeitos colaterais
○ Simplifica paralelização
LISP
● Primeira linguagem funcional
● Uma linguagem funcional "pura"
● Não possui variáveis
● Todos os dados são imutáveis
● Tipo de dados
○ Átomos: símbolos (identificadores) ou literais numéricos
○ Listas (o principal tipo de dados)
● Dados e programas possuem a mesma representação
LISP
● Tipos de dados (1, 3.14, 5/2, 10/4...)
● Expressões aritméticas simples
● Chamada de função: fatorial, igual, maior...
● Tipo de dados: lista
● Funções para listas: atom, car, cdr
● Definição de função
LISP

; Tipos de dados
> 1 ; inteiro

> 3.14 ; ponto flutuante

3.14

> 1/5 ; racional

1/5
LISP

; Uma lista (NOME ARG1 ARG2 ARG3 ... ARGN) é uma chamada de função
> (+ 1 2)

> (+ 1 2 3 4 5 6)

15

> (- 3 2 1)

> (* 2 3 4 5)

120
LISP

; Operações com números racionais


> (/ 2 3)

2/3

> (+ 2/3 1) ; 2/3 + 1 = 2/3 + 3/3

5/3

> 22/6 ; a fração 22/6 é simplificada

11/3

> (+ 6/2 2/3) ; 6/2 + 2/3 = 18/6 + 4/6 = 22/6

11/3
LISP

; Operações com números de ponto flutuante


> (/ 2 3 4) ; 2/3/4 = 2/12 = 1/6

1/6

> (/ 2.0 3)

0.666666666

> (/ 2.0 3 4)

0.166666667
LISP

; Expressões devem ser escritas em notação pré-fixa


> (+ 2 (* 3 4)) ;2+3*4

14

> (* (+ 2 3) 4) ; (2 + 3) * 4

20

> (/ 2.0 3)

0.666666666

> (/ 2.0 3 4)

0.166666667
LISP

; Criando uma lista


> (list 1 2 3 4)

(1 2 3 4)

> (list 1 (list 2 3) 4)

(1 (2 3) 4)

; Testando se alguma coisa é um átomo ou uma lista


> (atom 1)

> (atom (list 1 2 3))

NIL
LISP

; CAR ou FIRST: retorna o primeiro elemento de uma lista


> (CAR (list 1 2 3 4))

> (FIRST (list 1 2 3 4))

> (FIRST (list 1 (list 2 3) 4))

> (FIRST 1)

; erro
LISP

; CDR ou REST: retorna o restante da lista


> (CDR (list 1 2 3 4))

(2 3 4)

> (REST (list 1 (list 2 3) 4))

((2 3) 4)

> (REST (list 1 2))

(2)

> (REST (list 1))

NIL
LISP

; LISP Example function


; The following code defines a LISP predicate function
; that takes two lists as arguments and returns True
; if the two lists are equal, and NIL (false) otherwise
> (DEFUN lis_eq (lis1 lis2)
(COND
((ATOM lis1) (EQ lis1 lis2))
((ATOM lis2) NIL)
((lis_eq (FIRST lis1) (FIRST lis2)) (lis_eq (REST lis1) (REST lis2)))
(T NIL)
)
)

> (lis_eq (list 1 2 3) (list 1 2 3))

> (lis_eq (list 1 2) (list (1 2 3))

NIL
Scheme
● Originária da linguagem LISP, que é precursora da
maioria das linguagens funcionais

● Expressões nesta linguagem são escritas de forma


parentizada e pré-fixada
(função arg1 arg2 … argn)

● Principal distribuição: DrScheme


Scheme
● Fatorial

(define fatorial
(lambda (n)
(if (= n 0)
1
(* n (fatorial (- n 1))))))
Scheme
● Fatorial

(define pertence?
(lambda (el conj)
(if (null? conj)
'#f
(if (= (car conj) el)
'#t (pertence? el (cdr conj))))))
Haskell
● Linguagem funcional, das listadas, que mais sem
aproxima de definições matemáticas

● É fortemente tipada

● Pois um sistema de tipos bastante rebuscado,


fazendo inferência de tipos quando estes não são
fornecidos
Haskell
● Fatorial
fatorial :: Int -> Int
fatorial 0 = 1
fatorial n = fatorial (n-1) * n

OU

fatorial n
| n == 0 = 1
| otherwise = fatorial (n-1) * n

OU

fatorial n = if n == 0 then 1
else fatorial (n-1) * n
Linguagens Funcionais
● Programação "puramente" funcional é difícil
● Algumas tarefas são naturalmente associadas a
estados, como processamento de E/S
○ Leitura/escrita do teclado/de arquivos
● Na prática, linguagens "puramente" funcionais são
menos utilizadas
○ Multiparadigma permite empregar conceitos funcionais em
linguagens menos abstratas
Python Funcional
Python funcional
● Princípios norteantes
○ Uma função é um mapeamento da entrada para uma
saída única

A B A B

Função Relação binária


Python funcional
● Princípios norteantes
○ Uma função é um mapeamento da entrada para uma
saída única
■ O resultado de uma função depende exclusivamente dos
argumentos
■ Efeitos colaterais inexistentes ou restritos
■ Uma função chamada duas vezes com os mesmos argumentos
deve retornar o mesmo valor
Python funcional
● Princípios norteantes
○ A recursão substitui a iteração
■ Característica marcante do paradigma
○ Manipulação de coleções
■ Listas
■ Tuplas (listas imutáveis)
■ Dicionários
■ Conjuntos
Python funcional
● Princípios norteantes
○ Sem efeitos colaterais
○ Estritamente, sem atribuições
○ Exceção: em alguns casos, variáveis locais
○ Mas as funções não podem compartilhar estados!
■ Uma função não pode alterar um objeto
■ Não utilizamos variáveis globais
Python funcional
● Exemplos
○ Cálculo do fatorial
○ Funções CAR e CDR ou head() e tail()
○ Somar todos os elementos de uma lista
○ Testar se uma lista contém um elemento
○ Selecionar todos os números pares de uma lista
○ Encontrar o menor valor de uma lista
Python funcional
● Exceção para variáveis locais
○ Em algumas situações, é aceitável usar variáveis locais
○ Elas devem funcionar como apelidos
■ Para melhorar a legibilidade do código
■ Ou para evitar repetir uma recursão
○ Uma vez definido o valor da variável, ela não pode mais
ser alterado
Python funcional
● Aceitável

def menor(L):
if len(L) == 1:
return L[0]
else:
menor_resto = menor(L[1:])
if L[0] < menor_resto:
return L[0]
else:
return menor_resto
Python funcional
● Não aceitável

def menor(L):
res = L[0]
for x in L:
if x < res:
res = x
return res
Python funcional
● Melhor

def min(a, b):


if a < b:
return a
else:
return b

def menor(a, b):


if len(L) == 1
return L[0]
else:
return min(L[0], menor(L[1:]))
Taferas de Python funcional
● Retornar o menor elemento de uma lista
● Ordenar uma lista
● Encontrar o máximo divisor comum
○ Algoritmo de Euclides: subtraia o menor do maior até os
valores serem iguais
● Inverter uma lista
● Verificar se um número é primo
Funções de Ordem mais Alta
Funções em Python
● As funções de Python são objetos de primeira classe
porque suportam todas as operações disponíveis para
objetos de primeira classe
○ Uma função pode ser passada como argumento para
outra função
○ Uma função pode ser retornada por outra função

>>> escreve = print

#escreve <built-in function print>

>>> escreve("abc")
abc
Funções em Python
● Uma função de ordem mais alta é aquela que
○ Recebe outra função como argumento; ou
○ Retorna uma função como argumento

>>> def aplicar(fun, arg):


... return fun(arg)
...

>>> aplicar(print, "Hello, world!")


Hello, world!
Funções em Python
● Funções lambda

<lambda> ::= "lambda" [ <parâmetros> ] : <expressão>

<parâmetros> ::= <id> { , <id> }

>>> def quadrado(x):


... return x * x
...
Python só permite
>>> quadrado(6) funções lambda com
36 uma linha

>>> quad = lambda x : x * x

>>> quad(6)
36
Funções em Python
● A notação lambda permite criar uma função anônima,
sem vínculo a nenhum nome
○ lambda x : x * x
● Funções lambda podem ser vinculadas a variáveis ou
podem ser utilizadas em expressões
○ >>> aplicar(lambda x : x * x, 6)
○ 36
Map, filter e reduce
● Três importantes operações em linguagens funcionais
são
○ Map: mapeia um conjunto de valores para a imagem de
uma função
○ Filter: filtra uma coleção
○ Reduce: aplica uma função em uma coleção, reduzindo a
um único valor

● As funções map e filter retornam iteradores, que


podem ser convertidos em listas
Filter
● filter(função, lista)
○ Faz com que a função atue como um filtro sobre os
elementos da lista
○ Os elementos que são mapeados para um valor falso são
filtrados (removidos)

def par(x):
return x % 2 == 0

list(filter(par, [1, 2, 3, 4, 5, 6]))

Resultado: [2, 4, 6]
Map
● map(função, lista)
○ Utiliza uma função para transformar cada elemento da lista
○ Retorna uma nova lista com cada elemento mapeado por
meio da função

def quadrado(x):
return x ** 2

list(map(quadrado, [1, 2, 3, 4, 5, 6]))

Resultado: [1, 4, 9, 16, 25, 36]


Reduce
● reduce(função, lista)
○ A função deve ter dois parâmetros: um acumulador e um
elemento da lista
○ Inicialmente, o acumulador é o primeiro elemento da lista
■ Então o valor mapeado pela função se torna o acumulador para
o próximo elemento

from functools import reduce

def somador(acc, elem):


return acc + elem

reduce(somador, [1, 2, 3, 4, 5, 6])

Resultado: 21
Funções de ordem mais alta e lambda
● Não é necessário declarar cada função
separadamente com def
○ Podemos empregar funções lambda
○ As listas podem ser implícitas
○ Por exemplo, podemos empregar um iterador
■ list(range(6)): produz [0, 1, 2, 3, 4, 5]
■ list(range(1, 6)): produz [1, 2, 3, 4, 5]
A função range() retorna
■ list(range(1, 6, 2)): produz [1, 3, 5] uma série numérica no
intervalo enviado como
argumento
Funções de ordem mais alta e lambda
● Qual o quadrado dos números de 1 a 5?
○ Mapeie a lista com f(x) = x²
● Quais os números pares entre 0 e 10?
○ Filtre os elementos ímpares
● Qual o cubo dos números pares entre 0 e 10?
○ Filtre e mapeie a lista com f(x) = x³
○ Ou gere apenas os ímpares
● Qual a soma dos 10 primeiros inteiros?
○ Reduza cumulativamente para um valor único
Por quê?
● Vantagens de map, filter, reduce
○ Podem simplificar laços complexos (em programas
imperativos)
○ Podem ser encadeadas
○ Muitas computações podem ser reduzidas a essas três
operações
○ Facilmente distribuídas (paralelização)
Quantificadores
● Python possui dois quantificadores

○ Quantificador existencial ∃ (any)


■ Retorna verdadeiro se pelo menos um elemento da lista possui
um valor verdade
■ True, valores numéricos diferentes de 0 e 0.0 e strings e
coleções não vazias

○ Quantificador universal ∀ (all)


■ Retorna verdadeiro se todos os elementos da lista possuem
valor verdade
Quantificadores
● Número primo
○ n é primo se ¬∃k ∈ [2, n[ | n ≡ 0 (mod k)

>>> def primo(n):


... if n < 2: return False
... else: return not any(map(lambda k: n % k == 0, range(2, n)))

>>> primo(2)
True

>>> primo(5)
True

>>> primo(8)
False
Geradores e Avaliação
Preguiçosa
Avaliação Preguiçosa
● Linguagens imperativas normalmente usam avaliação
ansiosa (ou gulosa ou antecipada)
○ O resultado de uma expressão é calculado imediatamente
○ Normalmente, o comportamento de um programa depende
das mudanças de estado que ele sofre por meio de
expressões

>>> op1 = 0
>>> op2 = 1
>>> mul = op1 * op2
>>> op1 = 3
>>> print(mul)
0
Avaliação Preguiçosa
● Linguagens funcionais normalmente empregam
avaliação preguiçosa (ou atrasada)
○ Uma expressão somente é avaliada quando seu valor se
faz necessário
○ Exemplo em Haskell

evens = [0, 2..]


main = print(take 5 evens)
■ evens é uma lista infinita de números pares, mas o programa
principal apenas avalia os cinco primeiros elementos
Geradores e Iteradores
● Em Python, podemos obter avaliação preguiçosa
através de dois mecanismos distintos, mas muito
relacionados

○ Iteradores
■ Objetos que auxiliares que produzem uma sequência

○ Geradores
■ Funções ou expressões que constróem iteradores
Iteradores
● Um iterador é um objeto que produz uma sequência
○ Podemos definir uma classe que fornece um iterador
(usando POO)
○ Ou podemos transformar coleções em iteradores usando a
função iter()

>>> it = iter([2, 3, 5, 7])


>>> type(it)
list_iterator
Iteradores
● Iteradores podem ser percorridos com a função next()
ou podem ser utilizados no escopo de um for

>>> it = iter([2, 3, 5, 7])


>>> next(it) >>> it = iter([2, 3, 5, 7])
2 >>> for i in it:
>>> next(it) ... print(i)
3 2
>>> next(it) 3
5 5
>>> next(it) 7
7
Iteradores
● Observe que iteradores possuem um estado interno
○ O iterador só pode ser utilizado uma vez

>>> it = iter([2, 3, 5, 7])


>>> for i in it:
... print(i)
2
3
5
7
>>> for i in it:
... print(i) Não faz nada: o iterador foi
>>> totalmente consumido
Geradores
● Geradores são funções e expressões que produzem
iteradores
● Uma função que utiliza o comando yield é um gerador
● Quando o gerador é chamado, a função não é
executada
○ Em vez disso, um iterador é criado
● Cada vez que a função next() é chamada, o iterador
executa até o próximo yield
Geradores
>>> def gerador_simples():
... print("Primeiro yield")
... yield 1
... print("Segundo yield")
... yield 2
... print("Terceiro yield")
... yield 3

>>> g = gerador_simples() O corpo da função não é executado


ainda; apenas um iterador é construído
>>> next(g)
Primeiro yield
1
A cada chamada de next(), o corpo da
>>> next(g) função é avaliado. Cada yield produz o
Segundo yield próximo valor da sequência
2

>>> next(g)
Terceiro yield
3
Geradores
● Podemos associar um gerador a um estado interno
limitado para produzir uma sequência

>>> def fat(n):


... yield 1 # retorna 0!
... f = 1
... for i in range(1, n + 1):
... f *= i
... yield f
...
Geradores
● Uma versão recursiva poderia ser obtida com o
comando yield from

>>> def fat(n):


... yield 1
...
... def fat_n(x, i, n):
... if i <= n:
... yield x * i
... yield from fat_n(x * i, i + 1, n)
... else:
... return
...
... yield from fat_n(1, 1, n)
Entrada e Saída em Python
Funcional
Fluxos
● Em programação funcional, geradores são conhecidos
como fluxos (streams)
○ São objetos dos quais "fluem" sequências de dados,
possivelmente sem nenhum estado
○ Ou com estado interno restrito

● Podemos utilizar fluxos para fazer leitura de dados


Leitura do teclado em Python
● Podemos construir um iterador para fazer a leitura de
um caso de teste
○ Leitura de cada parte do caso de teste do problema "soma
exata"
■ Um inteiro N seguido de N inteiros

>>> def leSomaExata():


... N = int(input())
... for i in range(N):
... yield int(input())
Leitura do teclado em Python
● Podemos construir um iterador para fazer a leitura de
um caso de teste
○ Leitura da segunda parte do caso de teste do problema
"soma exata"
■ Um número Q seguido de Q consultas

>>> def leSomaExata():


... N = int(input())
... for i in range(N):
... yield int(input())
Mesmo gerador!
Leitura do teclado em Python
● Solução funcional

>>> def somaExata(lista, x):


... # retorna verdadeiro se existem dois elementos com soma x

>>> def leParte():


... N = int(input())
... for i in range(N):
... yield int(input())

>>> lista = list(leParte())

>>> for q in leParte():


... print("sim" if SomaExata(lista, q) else "nao")
Leitura do teclado em Python
● Para entradas que terminam com um sentinela,
podemos usar um comando return dentro do gerador
para finalizar o iterador
○ Exemplo: lê pares de linhas até que a segunda linha seja
um valor negativo
○ Retorna uma tupla a cada vez

>>> def lePares():


... while True:
... a = int(input())
... b = int(input())
... if b < 0: return
... yield (a, b)
Leitura linha por linha
● Python possui um gerador que lê a entrada linha por
linha
import sys
for line in sys.stdin:
print("linha = %s".format(line))

import sys
for line in sys.stdin:
print("linha = %s" % line)

import sys
for line in sys.stdin:
print(f"linha = {line}")
Leitura com eval
● Se o conteúdo da linha for uma expressão em Python,
ela pode ser automaticamente avaliada com eval
○ Isso é potencialmente perigoso
○ Use apenas se souber que a entrada é segura

entrada = eval(input())
Leitura com eval
● Em alguns casos, podemos associar diretamente eval
e sys.stdin para ler um caso de teste

import sys
for line in sys.stdin:
caso = eval(line)
# processa o caso de teste

● Versão funcional

import sys
for caso in map(eval, sys.stdin):
# processa o caso de teste
Compreensões de listas
Notação implícita de conjuntos
● Em Matemática Discreta, podemos representar um
conjunto implicitamente por meio de uma expressão
○ O quadrado dos números pares de 1 a 9
■ Q = {n² | n ∈ [1, 10[ ∧ n ≡ 0 (mod 2)}
■ Q = {4, 16, 36, 64}

● Em Python, uma lista pode ser expressa de forma


semelhante

[i ** 2 for i in range(1, 10) if i % 2 == 0]


Compressão de Listas
● Compreensão de lista ou list comprehension (LC) é
uma notação que substitui map e filter
○ Mapeamento através de uma expressão

[expressão for iterador in lista]

○ Equivalente a

res = []

for iterador in lista:

res.append(expressão)
Compressão de Listas
● LC pode ser associado a um condicional
○ Apenas os elementos para os quais a condição é
verdadeira são mapeados

[expressão for iterador in lista if condição]

○ Equivalente a

res = []
for iterador in lista:
if condição:
res.append(expressão)
Compressão de Listas
● Algumas pessoas (incluindo o criador de Python)
defendem que LC é mais simples e legível do que
funções lambda
● Qual parece mais legível?

lis = [-1, 10, 8, -8, 5, -6, 3, 11, -13, 27, 30]


rs = list(map(lambda x: x*x, filter(lambda x: x > 0, lis)))

lis = [-1, 10, 8, -8, 5, -6, 3, 11, -13, 27, 30]


rs = [x*x for x in lis if x > 0]
Compressão de Listas
● Algumas pessoas (incluindo o criador de Python)
defendem que LC é mais simples e legível do que
funções lambda
● E com funções nomeadas?

lis = [-1, 10, 8, 7, 5, -3, 3, 11, -13, 27, 30]


pares = lambda x: x % 2 == 0
div5 = lambda x: x/5
res = list(map(div5, filter(pares, lis)))

lis = [-1, 10, 8, 7, 5, -3, 3, 11, -13, 27, 30]


res = [x/5 for x in lis if x % 2 == 0]
Compressão de Listas
● Uma compreensão de lista entre parênteses é um
gerador
○ Tentando gerar 263 números pares

erro = [x for x in range(int(2**64)) if x % 2 == 0]

Não faça isto

○ Gerando até 263 números pares sob demanda com


avaliação preguiçosa

pares = (x for x in range(int(2**64)) if x % 2 == 0)

Não funciona em Python 2 (range não é gerador)


Compressão de Listas
● Podemos usar geradores, compreensão de listas e o
quantificador universal any para encontrar números
primos

def is_prime(n):
if n == 1: return False
return not any(n % k == 0 for k in range(2, n))

def primes(m):
return [n for n in range(1, m) if is_prime(n)]
Paradigma Funcional

Eduardo Feitosa
efeitosa@icomp.ufam.edu.br

Você também pode gostar