Python, Scheme e ML - Uma análise comparativa das linguagens de programação
Autor: Ruda Porto Filgueiras | Publicado: 2007-04-30T16:13:00-03:00

Durante o FLISOL  Salvador 2007 , evento em que participei apresentando uma palestra sobre Python, decidi que era hora de começar a escrever. Já fazia mais de um mês que eu havia decidido começar a escrever um blog sobre minhas experiências usando a linguagem Python, o servidor de aplicação Zope e CMS Plone.  O nome já estava registrado:  python-blog.blogspot.com, e o que mais estava faltando? Iniciativa. ;-)Na primeira postagem estou publicando um artigo que escrevi juntamente com dois colegas na disciplina de Engenharia e Software I (2006.2). Escrevê-lo me ajudou enxergar o quão poderosas são as linguagens  funcionais e o quanto Python herda desse paradigma. Além disso cheguei a conclusão que as linguagens funcionais deveriam ser mais ensinadas nos cursos de Ciência da Computação, talvez até com primeira linguagem! :-o    <!--   @page { margin: 2cm }   P { margin-bottom: 0.21cm }   H1 { margin-bottom: 0.21cm }   H1.western { font-family: "Arial", sans-serif; font-size: 16pt }   H1.cjk { font-family: "Andale Sans UI", "Arial Unicode MS"; font-size: 16pt }   H1.ctl { font-family: "Andale Sans UI", "Arial Unicode MS"; font-size: 16pt }   H2 { margin-bottom: 0.21cm }   H2.western { font-family: "Arial", sans-serif; font-size: 14pt; font-style: italic }   H2.cjk { font-family: "Andale Sans UI", "Arial Unicode MS"; font-size: 14pt; font-style: italic }   H2.ctl { font-family: "Andale Sans UI", "Arial Unicode MS"; font-size: 14pt; font-style: italic }   TD P { margin-bottom: 0cm }   A:link { color: #0000ff }  -->     Python, Scheme e ML  Uma análise comparativa das linguagens de programação.  Faculdade Ruy Barbosa Rudá Porto Filgueiras, Sergio Pacheco,  Adrienne Nogueira    Disciplina de Engenharia de Software I – 2006.2  Curso de Bacharelado em Ciência da Computação – Faculdade Ruy Barbosa(FRB)  Rua Theodomiro Batista, 422 – Rio Vermelho – Cep: 41.940-320 – Salvador – BA  rudazz@gmail.com, sergiorpacheco@gmail.com, adrieness_eu@yahoo.com.br 1. Resumo As linguagens de programação tem uma importância fundamental na nossa capacidade de expressar idéias e resolver problemas. A análise de diferentes linguagens possibilita o avaliação das escolhas realizadas em tempo de projeto, utilizando os critérios e conceitos da Engenharia de Software para  entender as escolhas dos projetistas e o resultado desas escolhas em cada linguagem. Palavras-chave: Linguagem de Programação, ML, Lisp, Scheme, Python, Projeto de Linguagem 2. Introdução           Esse artigo se propõe a comparar as características de três diferentes linguagens de programação. Scheme e ML são linguagens fundamentadas no paradigma funcional, de amplo uso, possuem diversas implementações e são muito utilizadas na área de matemática, lógica e inteligência artificial. A terceira e última linguagem é Python, que se diferencia por ser de propósito geral, multiparadigma e influenciada pelas lições de design de importantes linguagens, tais como: Ada, Scheme, SmalTalk, Módula 3.   Para realizar esse comparativo, selecionamos algumas características a serem estudadas e comparadas entre as linguagens. Isso nos permitirá avaliar as escolhas realizadas em tempo de projeto e seus benefícios e/ou contra-partidas utilizando os critérios da Engenharia de Software como parâmetro. As características abordadas são: simplicidade global, intruções de controle, suporte para abstração, manipulação de exceções e  verificação de tipos. 3. Simplicidade global           “A simplicidade global de uma linguagem afeta diretamente a sua legibilidade”, Sebesta (2005). As linguagens do paradigma funcional se fundamentam na simplicidade do conceito matemático de função, elementos e conjuntos. Em especial Scheme, que no seu projeto tem por objetivo ser minimalista, mantendo número de instruções básicas e palavras reservadas restritas ao mínimo necessário e ao mesmo tempo compatível com LISP.  Python se apoia nas idéias do projeto de Scheme para se manter simples e ao ser comparada com outras linguagens imperativas, em geral, possui menos instruções básicas e palavras reservadas, o que contribui para o seu fácil aprendizado. Assim como Scheme, Python procura implementar apenas um modo correto de se executar uma determinada operação, isso fortalece a simplicidade e consequentemente a legibilidade da linguagem.    ML não possui um grau de simplicidade global tão alto quanto Scheme, pois permite a programação imperativa e a declaração de tipos, embora não obrigue essa definição. Scheme não possui tipos de dados e apoia-se na conceito de átomos (elementos) e listas (conjuntos) para abstrair suas estruturas de dados. Todas estas linguagens são de alto nível, com alta capacidade de abstração o que torna essa simplicidade poderosa e expressiva. 4.  Instruções de controle           As instruções de controle são utilizadas para construir desvios e organizar o fluxo da execução dos programas. Nas linguangens imperativas, existem estruturas de controle para realizar a repetição e a seleção de determinados trechos de código a serem executados.  Python possui um conjunto reduzido de estruturas de controle, de forma a reduzir a complexidade da linguagem. Além disso a forma de expressar um loop for para percorer elementos de uma lista ou dicionário ou qualquer objeto que implemente alguns métodos especiais é simples e poderosa. Como ML, Python possui o recurso de compreensão de listas.  Scheme e ML possuem instruções de seleção simples as repetições são implementadas através da recursividade. Em Scheme a pilha de recursão não aumenta de acordo com a sua execução, o que garante que o espaço utilizado será constante, tornando a recursão mais segura e eficiente.  ML também possui recursos do paradigma imperativo, e por isso, possui instruções de controle semelhantes a linguagem C++, como if, else, case. Além disso seu mecanismo de seleção  baseados em encontro de padrões pode ser utlizado para selecionar parte da função que será executada a depender do valor recebido como parâmetro.   Exemplos:              Python    – compreensão de listas:                lista =    [1, 2, 3 ,4 ,5 ,6 ,7 ,8 ,9, 10]                lista =    [x for x in lista if x % 2 = 0]                [2, ,4    ,6, 8 , 10]        Scheme –    condicional e repetição com recursão                (DEFINE    (factorial n)                     (IF    (= n 0)                       1                       (* n (fatorial (- n 1)))))          ML    – encontro de padrões:     datatype shape =        point      | circle of real      | box of (real *    real)         fun area (point) =    0.0         | area (circle    r) = pi * sqr (r)              | area (box(w,h)) = w * h          5.  Suporte para abstração  “A abstração é a capacidade de modelar um problema de maneira a se concentrar nos aspectos importantes para esse sistema ou trecho expecífico de código, omitindo detalhes e facilitando a manipulaçãos das entidades ao separar as definições do que um programa faz, dos detalhes sobre como ele é implementado.”, Watt, David A. (1989).    O suporte para abstração em uma linguagem está relacionado a capacidade de definição de novos tipos de dados abstratos, denominada abstração de dados. Além disso, também está relacionada com a possibilidade de se abstrair um processo utilizando funções e procedimentos no paradigma funcional e imperativo.  O paradigma orientado a objetos funde esses dois conceitos ao permitir a definição de classes, com suas propriedades e métodos. E isso possui um impacto importante na capacidade de escrita e na confiabilidade, facilitando o reuso de código e a legibilidade.  As linguagens ML, Scheme e Python tratam as funções como tipos de dados de primeira ordem, o que as permite passar uma função como parâmetro de outras funções, armazenar funções como atributos ou elementos de uma estrutura de dados ou lista e também retorná-las como resultado de uma expressão, o que permite a criação de abstrações mais poderosas.  Um exemplo dessa capacidade é o uso da função interna map que mapeia os elementos de um conjunto aos elementos de um novo conjunto utilizando uma função que é passada como parâmetro e que será aplicada a cada elemento do conjunto inicial para gerar o novo conjunto. Exemplos:                ML        map(sqrt [1, 2, 3, 4])          Scheme        (MAP SQRT '(1 2 3 4))          Python        map(math.sqrt, [1,2,3,4])         Em todos os exemplos acima o resultado será uma nova lista contendo a raiz quadrada dos elementos da lista passada como parâmentro.  6. Verificação de Tipos Tradicionalmente na Engenharia de Software o sistema de verificação de tipos de uma linguagem de programação é classificado em dois grupos principais: estaticamente (fortemente) tipadas ou dinâmicamente (fracamente) tipadas. A capacidade de verificação de tipos de uma linguagem afeta diretamente a sua confiabilidade.Porém algumas linguagens, como Python, não se enquadram nesse modelo, pois são dinâmicamente tipadas e ao mesmo tempo fortemente tipadas.  Surgindo então uma diferenciação da definição tradicional onde podemos definir as linguagens como estáticamente ou dinâmicamente tipadas e fortemente ou fracamente tipadas. As linguagens estaticamente tipadas são aquelas no qual toda a variável, função e parâmentros tem um tipo bem definido, declarado pelo programador, e ela realiza a verficação de tipos em tempo de compilação.  Já nas linguagens dinamicamente tipadas, somente os valores tem tipos de dados definidos (tipos latentes), ou seja, uma variável ou parâmetro não tem um tipo definido e pode conter valores de diferentes tipos em diferentes momentos. Isso implica que a verificação de tipos deve ser  realizada em tempo de execução.  ML é uma linguagem estaticamente tipada e que possui um sistema de inferência de tipos robusto, tornando opcional a declaração de tipos. Scheme e Python são dinamicamente tipadas e também possuem a inferência dos tipos. Porém em todas elas o sistema de verficação de tipos não realiza a conversão implícita de um tipo de dados para outro, leventando uma exceção quando tipos inconsistentes são utilizados.    Python realiza uma nova vinculação de nome e espaço a cada attribuição de valor a uma variável, inferindo o tipo de dados do valor recebido. Além disso ela não possui definição de tipos nos parâmetros de funções ou métodos, deixando a cargo no programador o tratamento dos tipos recebidos e retornados. Exemplos:                Scheme    (+ 10 “16”)    ;The object “16”, passed as the second    argument to integer-add, is not the correct type.          Python    10 + “16”    TypeError: unsupported operand type(s) for +:    'int' and 'str'          ML    10 + “16”;    ! Type clash: expression of type string cannot    have type int         Podemos observar que não há a sobrecarga do operador “+” para concaternar uma string com um inteiro e a exceção levantada é resultado do sistema de verificação de tipos. 7.  Manipulação de exceções  Durante o desenvolvimento de um programa, diferentes tipos de erros precisam ser previstos e tratados para que se alcance um grau de confiabiliade adequado a cada necessidade, evitanto que o programa seja finalizado de forma inesperada.   Porém, se a linguagem utilizada não suportar nativamente o recurso de manipulação de execeções, quanto mais verificações forem necessárias, mais complexo o código vai ficar, e isso terá um impacto direto na legibilidade e no custo de implementação e manutenção.  ML, Scheme e Pyhon tem o suporte nativo ao tratamento de exceções, incluindo a definição de novos tipos de execeção. Scheme tem o suporte a exceções integrado ao seu interpretador de comandos, permitindo que o programador decida o que fazer quando uma exceção não tratada é levantada. As exceções em ML sempre são de tipo e podem ter um valor e um efeito associado. Em Python as exceções definidas pelo usuário utilizam o conceito de herança da orientação a objetos. Exception é a classe base na qual todas as outras exceções são derivadas. E como existe a unificação entre classes e tipos, e subclasses são subtipos, ao tratar uma exceção de um determinada classe todas as subclasses dessa exceção também serão tratadas. 8. Conclusão   Ao analisar as linguagens e comparar suas características percebemos que as escolhas em realizadas em tempo de projeto determinam as características das linguagens e os domínios para os quais elas serão mais indicadas.     ML e Scheme por serem fundamentadas no paradigma funcional, possuem uma excelente capacidade de escrita para o domínio da matemático, lógico e para sistemas simbólicos. Python foi desenvolvida para ser uma linguagem de propósito geral e consegue alcançar esse objetivo ao englobar o paradigma funcional, orientado a objetos e imperativo.   ML possui um alto grau de confiabilidade por ser estaticamente tipada e possuir um mecanismo de exceções nativo e um excelente suporte para abstração. Além disso ML permite o uso de estrturas das linguagens imperativas, aumentando a capacidade de escrita para domínios mistos que utilizem modelos formais e lógicas de negócios.   Python possui um grau de flexibilidade muito alto e isso tem impacto na sua confiabilidade, mas que é contrabalanceado com um modelo de objetos elegante, tratamento de exceções nativo e orientado a objetos e alta capacidade de abstração e recursos da programação funcional. A sua capacidade de escrita é alta para domínio de negócios e domínios mistos.  Segue abaixo um quadro resumo das características das linguagens:              <!--   @page { margin: 2cm }   TD P { margin-bottom: 0cm }   P { margin-bottom: 0.21cm }  -->                               ML          Scheme          Python              Simplicidade    Global          paradigma    imperativo    padronização    biblioteca    padrão extensa e inconsistente entre versões          Minimalista    padronização    tipos    de dados latentes          Minimalista    paradigma    imperativo    unificação    entre tipos e classes              Instruções    de controle          estruturas    semelhante as linguagens imperativas    encontro    de padrões    Compreensão    de listas          Recursividade    para repetição    Recursividade    eficiente    Estruturas    de seleção simples e múltipla          Possui    um conjunto reduzido de estruturas de controle: for, while, if e    with.    Recursividade    limitada    Compreensão    de listas              Suporte    a abstração          tratam    as funções como tipos de dados de primeira ordem    programação    funcional    estruturas    e registros              tratam    as funções como tipos de dados de primeira ordem    programação    funcional    listas    dinâmicas          Tudo    é objeto e tipo de dado de primeira ordem         orientação    a objetos elegante e consistente    Herança    múltipla              Verificações    de Tipos          Estaticamente    tipada    inferência    dos tipos    não    realiza a conversão implícita de tipos    permite    a declaração do tipo de uma variável          Dinâmicamente    tipada    inferência    dos tipos    não    realiza a conversão implícita de tipos    tipos    de dados latentes          Dinâmicamente    tipada    inferência    dos tipos    não    realiza a conversão implícita de tipos    tipos    de dados latentes                  Manipulação    de Exceções          suporte    nativo ao tratamento de exceções.    Exceções    podem conter valores e eventos associados          suporte    nativo ao tratamento de exceções.    suporte     implícito  integrado ao interpretador de comandos.   9. Bibliografia SEBESTA, Robert W. , Concepts of Programming Languages 7 ed. WATT, David A. , Programming Language Concepts and Paradigms 1 ed. DRAKE, Fred L., editor, Python Reference Manual - Release 2.519th September, 2006 http://docs.python.org/ref/ref.html HARPER, Robert, Programming in Standard ML (WORKING DRAFT OF AUGUST 25, 2006.) - http://www.cs.cmu.edu/~rwh/smlbook/online.pdf ABELSON, Harold, Structure and Interpretation  of Computer Programs, http://mitpress.mit.edu/sicp/full-text/book/book.html Wikipédia, a enciclopédia livre, http://pt.wikipedia.org/wiki/Programa%C3%A7%C3%A3o_funcional http://en.wikipedia.org/wiki/Python_%28programming_language%29 http://en.wikipedia.org/wiki/Scheme_%28programming_language%29 http://en.wikipedia.org/wiki/ML_language acessado em 10/11/2006.