Neste tópico vamos olhar para como se pode usar este estilo de programação (mais um) no Python:Tal como a Recursão a Programação Funcional é um tópico genuinamente avançado, que caso queiras podes ignorar, pelo menos por agora. AS técnicas da Programação Funcional, podem ter o seu uso no dia-a-dia de um programador e os adeptos do PF acreditam ser uma forma superior para o desenvolvimento de software.
A programação não deve ser confundida com a imperativa (ou procedural), mas também não se parece com a Programação orientada a objectos. É algo diferente (que as vezes apetece). Mas também não muito, aliás até porque os conceitos que vamos começar a explorar agora não são assim tão diferentes dos conceitos que já vimos até agora, apenas os vamos expressar de uma forma diferente. A filosofia por detrás de como estes conceitos são aplicados para resolver problemas, também é m pouco diferente.
A Programação Funcional é toda sobre expressões. Por acaso uma outra forma de descreve-la seria de Programação orientada por Expressãoes, uma vez visto que em PF tudo se reduz a uma expressão. Deves-te lembrar que uma expressão é uma colecção de de operações e variaveis que resultam num único valor. Sendo assim x == 5 é uma expressão booleana, 5 + (7-y) é uma expressão aritemetica e string.search("Olá Mundo") é uma expressão string. Mas esta última também chama uma função do módulo string, e como vamos ver mais a frente, funções são muito importantes na PF (já deve ter dado para ver, Programação Funcional, funções...hmmm!!).
As funções são usados como objectos na PF. Isto é, elas normalmente são passadas de um ponto para o outro dentro do mesmo programa, tal como as variavéis. Nós por acaso até já vimos exemplos disto, na secção Programando GUI, quando atribuimos o nome de uma função ao atributo command para controlarmos o Botão. Tratamos o função que lida com os eventos como um objecto, demos-lhe como referência ao Botão. Este conceito de passar funções de um lado para o outro, é o conceito chave da PF.
Na programação funcional os programas tendem a ter que lidar muito com listas.
E finalmente, há que dizer que a programação funcional centra-se no "quê", em vez do como, para resolução de um problema. Quer isto dizer, que a programação funcional deve descrever o problema a resolver em vez de se centrar no mecanismo de como o resolver. Existem várias linguagens de programação que pretendem implementar essa filosofia, uma das mais usadas é Haskeçç, podes ir ao web site ( www.haskell.org) onde podes encontrar inumeros documentos descrevendo esta filosofia de programção, como atambém podes encontrar muitas coisas acereca ad própria linguagem (convém). Na minha opinião pessoal é que os advogados desta linguagem são demasiados fanáticos por esta prespectica, por muito nobre que seja o objectivo.
Um puro programa funcional é estruturado por forma a capturar todas as intenções de um programa numa expressão. Cada linha de código dessa expressão, é por sua vez um uma declaração de uma das caracteristicas do programa (talvez encapsulada dentro de uma outra expressão) e avaliação de cada uma dessas linhas da expressão conduz a solução do problema.
Bom pelo menos na teoria. Se funciona? Bom, posso dizer que sim, para alguns
tipos de problema é uma técnica natural e poderosa. Mas infelizmente
para outros tipos de problema requer uma certa abstracção, na
analise, e é muito influenciada pelos principios matematicos. O código
resultante é (maioritariamente) muito mais legivél para o programador
mais leigo, e também muitas vezes é muito mais curto que o equivalente
feito numa programação imperativa e mmuito mais confiavél.
Foram estas últimas qualidades que chamaram a atenção de
muitos programadores que usavam os paradigmas da programação Imperativa
ou
OOP a investigar a programação funcional. Mesmo que não
venhas seguir esta filosofia religiosamente, ainda pode te fornecer umas ferramentas
muito úteis.
O Python fornece várias ferramentas que peremitem uma aproximação a este estilo. Estasa funções, podem se olhar como uma conviniência que podem ser feitas em Python de uma forma relativamente fácil. Mas o que é mais louvável aqui é que o Python permite uma aboradagem fucional, caso o programador/a o queira..
Agora vamos ver algumas dessas funções e ver como eles funcionam com alguns exemplos que vamos definir:
spam = ['pork','ham','spices']
numbers = [1,2,3,4,5]
def eggs(item):
print item
return item
Esta função usa uma outra função do Python (ou outra função definida pelo programador) e aplica-a a cada menbro da sequência, então sendo a espressão:
L = map(eggs, spam) print LResulta em que cada menbro do spam seja imprimido pela função eggs e que uma nova lista, neste caso igual ao spam, seja devolvida atribuida ao L.
É claro que podiamos ter feito a mesmissima coisa ao escrever:
for i in spam: print i L.append(i) print L
Mas repara no entanto que a função map, nos permite escrever o código sem a necessidade e um bloco de código. Pelo meu ponto de vista reduz a complexidade do programa em um nivél. E como vamos ver mais adiante é que o uso das funções em PF reduz a (relativa) complexidade do código ao eliminar os blocos de código.
Como o nome sugere, o filter, extrai cada elemento da sequência para o qual a função qualifica como verdadeiro. Para exemplo, considera a nossa lista de números, se quisermos criar uma nova lista só de números impares, poderiamos fazer o mesmo assim :
def isOdd(n): return (n%2 != 0) # usa o operador mod
L = filter(isOdd, numbers)
print L
Como alternativa:
def isOdd(n): return (n%2 != 0)
for i in numbers:
if isOdd(i):
l.append(i)
print L
Mas, mais uma vez repara que o codigo convencional, precisou de dois nivéis de indentação apra conseguir o mesmo resultado. E mais uma vez o aumento da indentações dentro do código e´encarrado como um aumento de complexidade do mesmo.
A função reduce, já não é tão obvia com as suas intenções. Esta função reduz uma lista a um único valor ao combinar os elementos via a função fornecida. Por exemplo, podiamos somar todos os valores de uma lista e obter o total assim:
def add(i,j): return i+j print reduce(add, numbers)
E tal como em todos os outros exemplos, poderiamos ter obtido o mesmo resultado usando uma programação mais convencional:
L = [] # empty list res = 0 for i in range(len(numbers)): # usando a indexação res = res + numbers[i] return res print res
Apesar de ambos produzirem o mesmo resultado, neste caso as coisas não são assim tão lineares. O que o reduce faz na realidade é chamar a função dada como argumento e a essa função ela fornece os dois primeiros elementos da lista e depois susbstitui o segundo elemento com o resultado da operação. Para uma melhor representação do reduce, podemos fazer isto:
L = numbers[:] # faz uma cópia do original while len(L) >= 2: i,j = L[0],L[1] # atribui a um tuple L = [i+j] + L[2:] print L[0]
Mais uma vez vemos que a técnica da PF reduz a complexidade do código ao evitar o uso de menos um bloco de código.
Uma das caracteristicas que podes ter notado até aqui é que as funções que se chamam para as funções PF, têm a tendência de serm muito curtas, muitas vezes sendo apenas uma linha de código. Para poupar o esforço que é criar uma serie de pequenas funções o fornece uma outra grande ajuda a PF - lambda
Lambda é um termo usado para nos referir a uma função anonima, isto é um bloco de código que pode ser executado como se fosse uma função, mas só que não tem um nome identificador. Lambdas podem ser definidas em qualquer parte de um programa onde uma expressão seja autorizada, o que significa que as podemos as usar dentro das funções da PF.
As lambdas tem este aspecto:
lambda <aListadeParâmetros> : <a o bloco de código que irá usa-los>
Então a função add, acima mencionada, poderia ser definida da seguinte forma:
add = lambda i,j: i+jE também podemos evitar a linha da definição da lambda, ao simplesmente cria-la dentro do reduce, assim:
print reduce(lambda i,j:i+j, numbers)
De uma forma semelhante, podiamos escrever as nossas funções map e filter desta forma:
L = map(lambda i: print i; i, spam) print L L = filter(lambda i: (i%2 != 0), numbers) print L
Apesar de estas funções terem a sua propria utlidade (quase o mesmo que dizer a sua propria individualidade), elas não são o suficiente para permitir que se diga que o Python tem um suporte completo para PF. As estruturas de controlo também têm que ser um pouco alteradas, ou substituidas, por uma forma mais propria da PF. Uma forma eficas de produzir resultado com isso é aproveitar a forma como o Python avalia as expressões booleanas.
Porque o Python utiliza como forma de avaliação, para as expressões booleanas, o metodo de short-circuit, exitem certas propriedades que podem ser exploradas. Apenas para recapitular o que short-circuit significa: quando uma expressão booleana é avaliada, a avaliação começa pelo lado esquerdo da expressão e depois até a ponta direita, parando essa mesma avaliação quando não for necessário prosseguir uma vez que isso não alteraria o resultado final.
Vendo uns exemplos concretos talvez ajude mais:
>>> def TRUE: ... print 'TRUE' ... return 1 # boolean TRUE ... >>>def FALSE: ... print 'FALSE' ... return 0 # boolean FALSE ...
Primeiro defimos umas funções que nos dizem quando é elas estão a ser executadas e retornam o valor dos seus nomes. Agora vamos usar estas mesmas expressões para explorar como é que as expressões booleanas são avaliadas:
>>>print TRUE() and FALSE() TRUE FALSE 0 >>>print TRUE() and TRUE() TRUE TRUE 1 >>>print FALSE() and TRUE() FALSE 0 >>>print TRUE() or FALSE() TRUE 1 >>>print FALSE() or TRUE() FALSE TRUE 1 >>>print FALSE() or FALSE() FALSE FALSE 0
Repara que somente SE a primeira parte de uma expressão AND é verdadeira apenas aí é que a segunda parte é avaliada. É que se a primeira parte for falsa, então não valrá a pena avaliar a segunda uma vez que o valor da expressão no seu TODO, jamais poderia ser verdadeiro..
Da mesma forma funciona a expressão OR, se a primeira parte for verdadeira, então não há necessidade de avaliar a segunda uma vez que a expressão no seu todo será verdadeira.
Podemos usar estas propriedades para reproduzir uma comportamento como os dos if e case. Supõem que tens um bocado d código que se assemelha a isto:
if TRUE(): print "It is True" else: print "It is False"
Podemos facilmente susbstitui-la com com um bocado de PF, assim:
V = (TRUE() and (print "It is True")) or \
(print "It is False")
Tenta trabalhar um pouco mais neste exemplo, substituindo o TRUE() pelo FALSE().
Então usando o metodo short-circuit podemos dizer que encontramos uma
forma de eliminar o if/else dos nossos programas. Deves-te lembrar também,
quando falamos da recurssão, que poderia ser utlizada para susbstituir
os loops. Então combinando estas ferramentas, podemos eliminar do nossos
códigos todas as formas e estruturas da programação convencional,
substituido-as por expressões. Este é o grande passo para entrar
dentro desse estilo de programação que é a Programação
Funcional.
Por estas alturas eves estar a pensar, em o que é que isto tudo realmente significa. Fica descansado que não és o único. Apesar da Programação Funcional ser muito apelatico aos academicos das Ciências Computacionais (muitas das vezes matenáticos), a maioria dos programadores usam essas técnicas de uma forma esporádica, de uma hibrida misturando-a com uma forma mais tradicional da programação, a imperativa.
Quando tens que usar funções como map, reduce ou o filter aos elementos de uma lista, e isso te parece sendo a solução natural para o teu problema, então não tenhas problemas em fazer tal. MAs apenas ocasionalmente é que irás achar a recursão um atécnica mais apropriada que o loop convencional. E ainda muito mais raramente irás achar a o uso desta técnica de short circuit mais apropriada ou conviniente que os if/else convencionais. Tal como todas as outras ferramentas da programação, não te dxeixes levar pela filosofia da coisa, mas sim aprende a usar as ferramentas de acordo com os problemas que estiveres a resolver.Mantém em mente que as alternativas existem!
Existe ainda um ponto mais a adicionar relativamente ao lambda. Existe uma area fora da PF em que o lambda encontra também o seu valor, e em definir controladores de eventos, quando estamos a programar GUI. Os controladores de eventos, são normalmente funções muito pequenas, ou vezes apenas chama uma função muito maior atráves de uma ligação dos argumentos. Em qualquer um dos casos o lambda pode ser usado como o controlador de eventos, para evitar a criação de pequenas funções, que apenas seriam usados uma vez. Então se bem te lembras como definir um botão nos GUI o lambda entra em cena assim:
b = Button(parent, text="Press Me",
command = lambda : print "I got pressed!")
b.pack()
Ou podes usar a técnica do bind:
b = Button(parent, text="Press me") b.bind(, lambda ev : print "Pressed")
E pronto, relativamente a PF é tudo, por agora existem uma serie de outros
recursos que podes usar caso queiras, abaixo deixo uma pequena lista delas.
Se alguem encontrar mais algum web site que pense valer a pena, envia-me um e-mail..
Em caso que tenhas alguma dúvida ou queiras comentar esta página envia-me um e-mail para: babyboy@oninet.pt