{ "metadata": { "name": "Capitulo16_Programacao_funcional" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "[Python para Desenvolvedores](http://ricardoduarte.github.io/python-para-desenvolvedores/#conteudo)\n", "===================================\n", "2ª edi\u00e7\u00e3o, revisada e ampliada\n", "-----------------------------------\n", "\n", "Cap\u00edtulo 16: Programa\u00e7\u00e3o funcional\n", "=============================\n", "_____________________________\n", "Programa\u00e7\u00e3o funcional \u00e9 um paradigma que trata a computa\u00e7\u00e3o como uma avalia\u00e7\u00e3o de fun\u00e7\u00f5es matem\u00e1ticas. Tais fun\u00e7\u00f5es podem ser aplicadas em sequ\u00eancias de dados (geralmente listas). S\u00e3o exemplos de linguagens funcionais: LISP, Scheme e Haskell (esta \u00faltima influenciou o projeto do Python de forma marcante).\n", "\n", "As opera\u00e7\u00f5es b\u00e1sicas do paradigma funcional s\u00e3o implementadas no Python pelas fun\u00e7\u00f5es builtin `map()`, `filter()`, `reduce()` e `zip()`.\n", "\n", "Lambda\n", "------\n", "No Python, *lambda* \u00e9 uma fun\u00e7\u00e3o an\u00f4nima composta apenas por express\u00f5es. As fun\u00e7\u00f5es lambda podem ter apenas uma linha, e podem ser atribu\u00eddas a uma vari\u00e1vel. Fun\u00e7\u00f5es lambda s\u00e3o muito usadas em programa\u00e7\u00e3o funcional.\n", "\n", "Sintaxe:\n", "\n", " lambda : \n", "\n", "Exemplo:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Amplitude de um vetor 3D\n", "amp = lambda x, y, z: (x ** 2 + y ** 2 + z ** 2) ** .5\n", "\n", "print amp(1, 1, 1)\n", "print amp(3, 4, 5)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "1.73205080757\n", "7.07106781187\n" ] } ], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Fun\u00e7\u00f5es *lambda* consomem menos recursos computacionais que as fun\u00e7\u00f5es convencionais, por\u00e9m s\u00e3o mais limitados.\n", "\n", "Mapeamento\n", "----------\n", "O mapeamento consiste em aplicar uma fun\u00e7\u00e3o a todos os itens de uma sequ\u00eancia, gerando outra lista contendo os resultados e com o mesmo tamanho da lista inicial.\n", "\n", "![Exemplo de mapeamento](files/bpypd_diags9.png)\n", "\n", "No Python, o mapeamento \u00e9 implementado pela fun\u00e7\u00e3o `map()`.\n", "\n", "Exemplos:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]\n", "\n", "# log na base 10\n", "from math import log10\n", "print map(log10, nums)\n", "\n", "# Dividindo por 3\n", "print map(lambda x: x / 3, nums)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[0.0, 0.3010299956639812, 0.47712125471966244, 0.6020599913279624, 0.6989700043360189, 0.7781512503836436, 0.8450980400142568, 0.9030899869919435, 0.9542425094393249, 1.0, 1.041392685158225, 1.0791812460476249]\n", "[0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4]\n" ] } ], "prompt_number": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ "A fun\u00e7\u00e3o `map()` sempre retorna uma lista.\n", "\n", "Filtragem\n", "---------\n", "Na filtragem, uma fun\u00e7\u00e3o \u00e9 aplicada em todos os itens de uma sequ\u00eancia, se a fun\u00e7\u00e3o retornar um valor que seja avaliado como verdadeiro, o item original far\u00e1 parte da sequ\u00eancia resultante.\n", "\n", "![Exemplo de filtragem](files/bpypd_diags10.png)\n", "\n", "No Python, a filtragem \u00e9 implementada pela fun\u00e7\u00e3o `filter()`.\n", "\n", "Exemplo:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Selecionando apenas os \u00edmpares\n", "print filter(lambda x: x % 2, nums)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[1, 3, 5, 7, 9, 11]\n" ] } ], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "A fun\u00e7\u00e3o `filter()` aceita tamb\u00e9m fun\u00e7\u00f5es *lambda*, al\u00e9m de fun\u00e7\u00f5es convencionais.\n", "\n", "Redu\u00e7\u00e3o\n", "-------\n", "Redu\u00e7\u00e3o significa aplicar uma fun\u00e7\u00e3o que recebe dois par\u00e2metros, nos dois primeiros elementos de uma sequ\u00eancia, aplicar novamente a fun\u00e7\u00e3o usando como par\u00e2metros o resultado do primeiro par e o terceiro elemento, seguindo assim at\u00e9 o final da sequ\u00eancia. O resultado final da redu\u00e7\u00e3o \u00e9 apenas um elemento.\n", "\n", "![Exemplo de redu\u00e7\u00e3o](files/bpypd_diags11.png)\n", "\n", "Exemplos de redu\u00e7\u00e3o, que \u00e9 implementada no Python pela fun\u00e7\u00e3o `reduce()`:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "nums = range(100)\n", "\n", "# Soma com reduce (pode concatenar strings)\n", "print reduce(lambda x, y: x + y, nums)\n", "\n", "# Soma mais simples, mas s\u00f3 para n\u00fameros\n", "print sum(nums)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "4950\n", "4950\n" ] } ], "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": [ "A fun\u00e7\u00e3o `reduce()` pode ser usada para calcular fatorial:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Calcula o fatorial de n\n", "def fat(n):\n", " return reduce(lambda x, y: x * y, range(1, n))\n", "\n", "print fat(6)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "120\n" ] } ], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "A partir da vers\u00e3o 2.6, o m\u00f3dulo *math* traz uma fun\u00e7\u00e3o que calcula fatorial chamada factorial().\n", "\n", "Transposi\u00e7\u00e3o\n", "------------\n", "Transposi\u00e7\u00e3o \u00e9 construir uma s\u00e9rie de sequ\u00eancias a partir de outra s\u00e9rie de sequ\u00eancias, aonde a primeira nova sequ\u00eancia cont\u00e9m o primeiro elemento de cada sequ\u00eancia original, a segunda nova sequ\u00eancia cont\u00e9m o segundo elemento de cada sequ\u00eancia original, at\u00e9 que alguma das sequ\u00eancias originais acabe.\n", "\n", "![Exemplo de transposi\u00e7\u00e3o](files/bpypd_diags12.png)\n", "\n", "Exemplo de transposi\u00e7\u00e3o, que \u00e9 implementada no Python pela fun\u00e7\u00e3o `zip()`:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Uma lista com ('a', 1), ('b', 2), ...\n", "from string import ascii_lowercase\n", "print zip(ascii_lowercase, range(1, 100))\n", "\n", "# Transposta de uma matriz\n", "matriz = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]\n", "print zip(*matriz)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7), ('h', 8), ('i', 9), ('j', 10), ('k', 11), ('l', 12), ('m', 13), ('n', 14), ('o', 15), ('p', 16), ('q', 17), ('r', 18), ('s', 19), ('t', 20), ('u', 21), ('v', 22), ('w', 23), ('x', 24), ('y', 25), ('z', 26)]\n", "[(1, 4, 7), (2, 5, 8), (3, 6, 9)]\n" ] } ], "prompt_number": 6 }, { "cell_type": "markdown", "metadata": {}, "source": [ "A fun\u00e7\u00e3o `zip()` sempre retorna uma lista de tuplas.\n", "\n", "*List Comprehension*\n", "--------------------\n", "Em computa\u00e7\u00e3o, *List Comprehension* \u00e9 uma constru\u00e7\u00e3o que equivale a uma nota\u00e7\u00e3o matem\u00e1tica do tipo:\n", "\n", "$$ S = \\\\{ x^{2} \\forall \\in \\mathbb{N}, x \\geq 20 \\\\} $$\n", "\n", "Ou seja, S \u00e9 o conjunto formado por x ao quadrado para todo x no conjunto dos n\u00fameros naturais, se x for maior ou igual a 20.\n", "\n", "Sintaxe:\n", "\n", " lista = [ for in if ]\n", "\n", "Exemplo:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]\n", "\n", "# Eleve os \u00edmpares ao quadrado\n", "print [ x**2 for x in nums if x % 2 ]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[1, 9, 25, 49, 81, 121]\n" ] } ], "prompt_number": 7 }, { "cell_type": "markdown", "metadata": {}, "source": [ "*List Comprehension* \u00e9 mais eficiente do que usar as fun\u00e7\u00f5es `map()` e `filter()` tanto em termos de uso de processador quanto em consumo de mem\u00f3ria.\n", "\n", "*Generator Expression*\n", "----------------------\n", "*Generator Expression* \u00e9 uma express\u00e3o que se assemelha ao *List Comprehension*, por\u00e9m funciona como um gerador.\n", "\n", "Exemplo:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]\n", "\n", "# Eleve os \u00edmpares ao quadrado\n", "gen = ( x**2 for x in nums if x % 2 )\n", "\n", "# Mostra os resultados\n", "for num in gen:\n", " print num" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "1\n", "9\n", "25\n", "49\n", "81\n", "121\n" ] } ], "prompt_number": 8 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Outro exemplo:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Uma lista de tuplas (artista, faixa):\n", "instrumentais = [('King Crimson', 'Fracture'),\n", " ('Metallica','Call of Ktulu'),\n", " ('Yes', 'Mood for a Day'),\n", " ('Pink Floyd', 'One of This Days'),\n", " ('Rush', 'YYZ')]\n", "\n", "# Filtra e ordena apenas as faixas de artistas anteriores a letra N\n", "print sorted(faixa[-1] + ' / ' + faixa[0]\n", " for faixa in instrumentais if\n", " faixa[0].upper() < 'N')" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "['Call of Ktulu / Metallica', 'Fracture / King Crimson']\n" ] } ], "prompt_number": 9 }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Generator Expression* usa menos recursos do que o *List Comprehension* equivalente, pois os itens s\u00e3o gerados um de cada vez, apenas quando necess\u00e1rio, economizando principalmente mem\u00f3ria." ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "" ], "output_type": "pyout", "prompt_number": 1, "text": [ "" ] } ], "prompt_number": 1 } ], "metadata": {} } ] }