1. Construindo Abstrações com Procedimentos
Os atos da mente, nos quais ela exerce seu poder sobre idéias simples, são principalmente estes três: 1. Combinar várias idéias simples em uma só, e assim são feitas todas as idéias complexas. 2. O segundo é reunir duas idéias, simples ou complexas, e colocá-las lado a lado de modo a vê-las ao mesmo tempo sem uni-las, obtendo assim todas as suas relações. 3. O terceiro é separá-las de todas as outras idéias que os acompanham em sua existência real: isso é chamado de abstração, e assim todas as suas idéias gerais são feitas.
John Locke, Um Ensaio Sobre o Entendimento Humano (1960)
Estamos prestes a estudar a ideia de um processo computacional. Processos computacionais são seres abstratos que habitam computadores. À medida que evoluem, os processos manipulam outras coisas abstratas chamadas dados. A evolução de um processo é dirigida por um padrão de regras denominado programa. As pessoas criam programas para direcionar processos. Com efeito, nós conjuramos os espíritos do computador com nossos feitiços.
Um processo computacional é de fato muito parecido com a ideia de espírito por um feiticeiro. Não pode ser visto ou tocado. Nem é composto de matéria. No entanto, é muito real. Pode realizar trabalho intelectual. Pode responder a perguntas. Pode afetar o mundo despendendo dinheiro em um banco ou controlando um braço robótico em uma fábrica. Os programas que usamos para conjurar processos são como os feitiços de um feiticeiro. Eles são cuidadosamente compostos de expressões simbólicas em linguagens de programação arcanas e esotéricas que prescrevem as tarefas que queremos que nossos processos realizem.
Um processo computacional, em um computador funcionando corretamente, executa programas com precisão e exatidão. Assim, como o aprendiz de feiticeiro, os programadores novatos devem aprender a compreender e antecipar as consequências de sua conjuração. Mesmo pequenos erros (geralmente chamados de bugs ou falhas) em programas podem ter consequências complexas e imprevistas.
Felizmente, aprender a programar é consideravelmente menos perigoso do que aprender feitiçaria, porque os espíritos com os quais lidamos são convenientemente contidos de forma segura. A programação do mundo real, no entanto, requer cuidado, experiência e sabedoria. Um pequeno bug em um programa de design auxiliado por computador, por exemplo, pode levar ao colapso catastrófico de um avião ou de uma represa ou à autodestruição de um robô industrial.
Os engenheiros de software mestres têm a capacidade de organizar programas para que possam estar razoavelmente seguros de que os processos resultantes realizarão as tarefas pretendidas. Eles podem visualizar o comportamento de seus sistemas com antecedência. Eles sabem como estruturar programas para que problemas imprevistos não levem a consequências catastróficas e, quando surgem problemas, eles podem depurar seus programas. Sistemas computacionais bem projetados, como automóveis ou reatores nucleares bem projetados, são projetados de maneira modular, para que as peças possam ser construídas, substituídas e depuradas separadamente.
Programando em Lisp
Precisamos de uma linguagem apropriada para descrever processos, e vamos usar para isso a linguagem de programação Lisp. Assim como nossos pensamentos cotidianos são geralmente expressos em nossa linguagem natural (como português, inglês, francês ou japonês) e as descrições de fenômenos quantitativos são expressas com notações matemáticas, nossos pensamentos procedimentais serão expressos em Lisp. Lisp foi inventado no final dos anos 1950 como um formalismo para raciocinar sobre o uso de certos tipos de expressões lógicas, chamadas equações de recursão, como um modelo para computação. A linguagem foi concebida por John McCarthy e é baseada em seu artigo "Funções Recursivas de Expressões Simbólicas e Sua Computação por Máquina" (McCarthy 1960).
Apesar de seu início como um formalismo matemático, Lisp é uma linguagem de programação prática. Um interpretador Lisp é uma máquina que realiza processos descritos na linguagem Lisp. O primeiro interpretador Lisp foi implementado por McCarthy com a ajuda de colegas e alunos do Grupo de Inteligência Artificial do Laboratório de Pesquisa de Eletrônica do MIT e no Centro de Computação do MIT.*1 Lisp, cujo nome é um acrônimo para LISt Processing (Processamento de Listas), foi projetada para fornecer recursos de manipulação de símbolos para atacar problemas de programação, como diferenciação simbólica e integração de expressões algébricas. Incluiu, para esse propósito, novos objetos de dados conhecidos como átomos e listas, o que o diferenciava de maneira impressionante de todas as outras linguagens do período.
Lisp não foi o produto de um esforço de design combinado. Em vez disso, ele evoluiu informalmente de maneira experimental em resposta às necessidades dos usuários e a considerações de implementação pragmáticas. A evolução informal do Lisp continuou ao longo dos anos, e a comunidade de usuários do Lisp tradicionalmente resistiu às tentativas de promulgar qualquer definição "oficial" da linguagem. Esta evolução, juntamente com a flexibilidade e elegância da concepção inicial, permitiu ao Lisp, que é a segunda linguagem mais antiga e amplamente utilizada hoje (apenas o Fortran é mais antigo), adaptar-se continuamente para abranger as ideias mais modernas sobre design de programas. Assim, Lisp é agora uma família de dialetos, que, embora compartilhe a maioria das características originais, podem diferir uns dos outros de maneiras significativas. O dialeto do Lisp usado neste livro é denominado Scheme.*2
Por causa de seu caráter experimental e sua ênfase na manipulação de símbolos, Lisp foi inicialmente muito ineficiente para cálculos numéricos, pelo menos em comparação com Fortran. Ao longo dos anos, no entanto, os compiladores Lisp foram desenvolvidos para traduzir programas em código de máquina que podem realizar cálculos numéricos de forma razoavelmente eficiente. E para aplicações especiais, Lisp tem sido usado com grande eficácia.*3 Embora Lisp ainda não tenha superado sua antiga reputação como irremediavelmente ineficiente, Lisp agora é usado em muitas aplicações onde a eficiência não é a preocupação central. Por exemplo, Lisp se tornou a linguagem de escolha para linguagens de shell de sistema operacional e para linguagens de extensão para editores e sistemas de design auxiliado por computador.
Se Lisp não é uma linguagem convencional, por que a estamos usando como estrutura para nossa discussão de programação? Porque a linguagem possui características únicas que a tornam um meio excelente para estudar importantes construções de programação e estruturas de dados e para relacioná-las às características linguísticas que as suportam. O mais significativo desses recursos é o fato de que as descrições Lisp de processos, chamadas procedimentos, podem ser representadas e manipuladas como dados Lisp. A importância disso é que existem técnicas poderosas de design de programa que contam com a habilidade de obscurecer a distinção tradicional entre dados "passivos" e processos "ativos". Como iremos descobrir, a flexibilidade do Lisp em lidar com procedimentos como dados o torna uma das linguagens mais convenientes que existem para explorar essas técnicas. A capacidade de representar procedimentos como dados também torna o Lisp uma excelente linguagem para escrever programas que devem manipular outros programas como dados, como interpretadores e compiladores que suportam linguagens de computador. Acima e além dessas considerações, programar em Lisp é muito divertido.
Last updated
Was this helpful?