Prefácio da Primeira Edição

Um computador é como um violino. Você pode imaginar um novato tentando primeiro um fonógrafo e depois um violino. Este último, ele diz, soa terrível. Esse é o argumento que ouvimos de nossos humanistas e da maioria de nossos cientistas da computação. Programas de computador são bons, eles dizem, para propósitos específicos, mas não são flexíveis. Nem é um violino, ou uma máquina de escrever, até que você aprenda a usá-lo.

—Marvin Minsky, Por que Programação é um Bom Meio para Expressar Ideias Mal Compreendidas e Formuladas de Forma Desleixada

“Estrutura e Interpretação de Programas de Computador” é a disciplina introdutória em ciência da computação no Instituto de Tecnologia de Massachusetts. É obrigatória para todos os alunos do MIT que se especializam em engenharia elétrica ou em ciência da computação, como um quarto do “currículo básico comum”, que também inclui duas disciplinas sobre circuitos e sistemas lineares e uma disciplina sobre o design de sistemas digitais. Estivemos envolvidos no desenvolvimento desta disciplina desde 1978, e temos ensinado este material em sua forma atual desde o outono de 1980 para entre 600 e 700 alunos por ano. A maioria desses alunos teve pouca ou nenhuma formação formal em computação, embora muitos tenham brincado um pouco com computadores e alguns tenham tido experiência extensa em programação ou design de hardware.

Nosso design desta disciplina introdutória de ciência da computação reflete duas grandes preocupações. Primeiro, queremos estabelecer a ideia de que uma linguagem de computador não é apenas uma forma de fazer um computador realizar operações, mas sim um novo meio formal para expressar ideias sobre metodologia. Assim, os programas devem ser escritos para serem lidos por pessoas, e apenas incidentalmente para serem executados por máquinas. Segundo, acreditamos que o material essencial a ser abordado por uma disciplina neste nível não é a sintaxe de construções específicas de linguagens de programação, nem algoritmos engenhosos para calcular funções específicas de forma eficiente, nem mesmo a análise matemática de algoritmos e os fundamentos da computação, mas sim as técnicas usadas para controlar a complexidade intelectual de grandes sistemas de software.

Nosso objetivo é que os alunos que completem esta disciplina tenham uma boa noção dos elementos de estilo e da estética da programação. Eles devem dominar as principais técnicas para controlar a complexidade em um sistema grande. Eles devem ser capazes de ler um programa de 50 páginas, se ele for escrito em um estilo exemplar. Eles devem saber o que não ler e o que não precisam entender em um determinado momento. Eles devem se sentir seguros ao modificar um programa, mantendo o espírito e o estilo do autor original.

Essas habilidades não são exclusivas da programação de computadores. As técnicas que ensinamos e utilizamos são comuns a todo o design de engenharia. Controlamos a complexidade construindo abstrações que escondem detalhes quando apropriado. Controlamos a complexidade estabelecendo interfaces convencionais que nos permitem construir sistemas combinando peças padrão e bem compreendidas de forma “mix and match”. Controlamos a complexidade estabelecendo novas linguagens para descrever um design, cada uma das quais enfatiza aspectos particulares do design e desenfatiza outros.

Subjacente à nossa abordagem desta disciplina está nossa convicção de que “ciência da computação” não é uma ciência e que sua importância tem pouco a ver com computadores. A revolução do computador é uma revolução na forma como pensamos e na forma como expressamos o que pensamos. A essência dessa mudança é o surgimento do que pode ser melhor chamado de epistemologia procedural—o estudo da estrutura do conhecimento de um ponto de vista imperativo, em oposição ao ponto de vista mais declarativo adotado por disciplinas matemáticas clássicas. A matemática fornece uma estrutura para lidar precisamente com noções de “o que é”. A computação fornece uma estrutura para lidar precisamente com noções de “como fazer”.

No ensino do nosso material, usamos um dialeto da linguagem de programação Lisp. Nunca ensinamos formalmente a linguagem, porque não precisamos. Apenas a usamos, e os alunos a aprendem em alguns dias. Essa é uma grande vantagem das linguagens semelhantes ao Lisp: Elas têm muito poucas formas de formar expressões compostas e quase nenhuma estrutura sintática. Todas as propriedades formais podem ser cobertas em uma hora, como as regras do xadrez. Após um curto período, esquecemos os detalhes sintáticos da linguagem (porque não há nenhum) e passamos às questões reais—descobrir o que queremos computar, como vamos decompor problemas em partes gerenciáveis e como vamos trabalhar nas partes. Outra vantagem do Lisp é que ele suporta (mas não impõe) mais das estratégias de grande escala para decomposição modular de programas do que qualquer outra linguagem que conhecemos. Podemos fazer abstrações de procedimentos e dados, podemos usar funções de ordem superior para capturar padrões comuns de uso, podemos modelar estado local usando atribuição e mutação de dados, podemos vincular partes de um programa com fluxos e avaliação preguiçosa, e podemos facilmente implementar linguagens embutidas. Tudo isso está embutido em um ambiente interativo com excelente suporte para design, construção, teste e depuração incremental de programas. Agradecemos a todas as gerações de magos do Lisp, começando com John McCarthy, que forjaram uma ferramenta fina de poder e elegância sem precedentes.

Scheme, o dialeto do Lisp que usamos, é uma tentativa de unir o poder e a elegância do Lisp e do Algol. Do Lisp, tomamos o poder metalinguístico que deriva da sintaxe simples, da representação uniforme de programas como objetos de dados e do heap alocado com coleta de lixo. Do Algol, tomamos o escopo léxico e a estrutura de blocos, que são presentes dos pioneiros do design de linguagens de programação que estavam no comitê do Algol. Desejamos citar John Reynolds e Peter Landin por suas percepções sobre a relação do λ-cálculo de Church com a estrutura de linguagens de programação. Também reconhecemos nossa dívida com os matemáticos que exploraram esse território décadas antes dos computadores aparecerem. Esses pioneiros incluem Alonzo Church, Barkley Rosser, Stephen Kleene e Haskell Curry.