-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbook-Z-H-25.html
More file actions
46 lines (32 loc) · 12.1 KB
/
book-Z-H-25.html
File metadata and controls
46 lines (32 loc) · 12.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ops="http://www.idpf.org/2007/ops">
<!-- Generated from TeX source by tex2page, v 4o,
(c) Dorai Sitaram, http://www.cs.rice.edu/~dorai/tex2page -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta http-equiv="Content-Type: text/html; charset=utf-8"/>
<title>Estrutura e Interpretação de Programas de Computador</title>
<link rel="stylesheet" type="text/css" href="book-Z-C.css" title="default"/>
</head>
<body>
<a name="%_chap_4" id="%_chap_4"/>
<h1 class="chapter">
<div class="chapterheading"><a href="book-Z-H-4.html#%_toc_%_chap_4">Capítulo 4</a></div></h1><p>
<a href="book-Z-H-4.html#%_toc_%_chap_4">Abstração metalinguística</a></p><p>
</p><p>
</p><div align="right">
<table width="60%"><tr><td>
<span class="epigraph">
<p>
<tt>…</tt> É em palavras que a mágica é – Abracadabra, abra-te sésamo e o resto – mas as palavras mágicas em uma história não são mágicas na próxima. A verdadeira mágica é entender quais palavras funcionam, e quando e para quê; o truque é aprender o truque.<br/><tt>…</tt> E essas palavras são feitas das letras do nosso alfabeto: algumas dúzias de rabiscos podemos desenhar com a caneta. Essa é a chave! E o tesouro também, se pudermos pôr as mãos nele! É como se – como se a chave do tesouro <em>fosse</em> o tesouro!</p><p>
<a name="%_idx_4188" id="%_idx_4188"/>John Barth, <em>Chimera</em></p><p>
</p></span>
</td></tr></table></div>
<p/><p>Em nosso estudo do projeto de programas, vimos que programadores controlam a complexidade de seus projetos com as mesmas técnicas gerais usadas pelos projetistas de todos os sistemas complexos. Eles combinam elementos primitivos para formar objetos compostos, abstraem objetos compostos para formar blocos de construção de nível superior e preservam a modularidade adotando visualizações apropriadas em larga escala da estrutura do sistema. Para ilustrar essas técnicas, usamos o Lisp como uma linguagem para descrever processos e construir objetos e processos de dados computacionais para modelar fenômenos complexos no mundo real. No entanto, ao enfrentarmos problemas cada vez mais complexos, descobriremos que o Lisp, ou qualquer linguagem de programação fixa, não é suficiente para nossas necessidades. Devemos procurar constantemente novas linguagens para expressar nossas ideias com mais eficácia. Estabelecer novas linguagens é uma estratégia poderosa para controlar a complexidade no projeto de engenharia. Geralmente podemos aprimorar nossa capacidade de lidar com um problema complexo adotando uma nova linguagem que nos permite descrever (e, portanto, pensar sobre) o problema de uma maneira diferente, usando primitivas, meios de combinação e meios de abstração particularmente adequado para o problema em questão.<a name="call_footnote_Temp_508" href="#footnote_Temp_508" id="call_footnote_Temp_508"><sup><small>1</small></sup></a></p><p>
<a name="%_idx_4190" id="%_idx_4190"/><a name="%_idx_4192" id="%_idx_4192"/>A programação é dotada de uma infinidade de linguagens. Existem linguagens físicos, como as linguagens de máquina para computadores específicos. Essas linguagens estão preocupadas com a representação de dados e controle em termos de bits individuais de armazenamento e instruções primitivas da máquina. O programador de linguagem de máquina está preocupado com o uso do hardware fornecido para montar sistemas e utilitários para a implementação eficiente de cálculos com recursos limitados. Linguagens de alto nível, montadas sob o substrato de linguagem de máquina, ocultam preocupações sobre a representação de dados como coleções de bits e a representação de programas como sequências de instruções primitivas. Essas linguagens possuem meios de combinação e abstração, como a definição de procedimentos, que são apropriados para a organização de sistemas em larga escala.</p><p>
<a name="%_idx_4194" id="%_idx_4194"/><a name="%_idx_4196" id="%_idx_4196"/><em>Abstração metalinguística</em> – estabelecendo novas linguagens – desempenha um papel importante em todos os ramos do projeto de engenharia. É particularmente importante para a programação de computadores, pois na programação não apenas podemos formular novas linguagens, mas também podemos implementá-las construindo avaliadores. Um <a name="%_idx_4198" id="%_idx_4198"/><em>avaliador</em> (ou <em>interpretador</em>) para uma linguagem de programação é um procedimento que, quando aplicado a uma expressão da linguagem, executa as ações necessárias para avaliar essa expressão.</p><p>Não é exagero considerar isso como a ideia mais fundamental da programação:</p><blockquote>O avaliador, que determina o significado das expressões em uma linguagem de programação, é apenas outro programa.</blockquote>Apreciar esse ponto é mudar nossas imagens de nós mesmos como programadores. Chegamos a nos ver como projetistas de linguagens, e não apenas como usuários de projetos projetados por outros.<p>De fato, podemos considerar quase qualquer programa como o avaliador de alguma linguagem. Por exemplo, o sistema de manipulação polinomial da seção <a href="book-Z-H-18.html#%_sec_2.5.3">2.5.3</a> incorpora as regras da aritmética polinomial e as implementa em termos de operações em dados estruturados em lista. Se incrementarmos esse sistema com procedimentos para ler e imprimir expressões polinomiais, teremos o núcleo de uma linguagem de propósito especial para lidar com problemas em matemática simbólica. O simulador de lógica digital da seção <a href="book-Z-H-22.html#%_sec_3.3.4">3.3.4</a> e o propagador de restrições da seção <a href="book-Z-H-22.html#%_sec_3.3.5">3.3.5</a> são linguagens legítimas por si só, cada uma com suas próprias primitivas, meio de combinação e meios de abstração. Visto dessa perspectiva, a tecnologia para lidar com sistemas de computação em larga escala se funde com a tecnologia para a construção de novas linguagens de computador, e a <a name="%_idx_4200" id="%_idx_4200"/>ciência da computação em si se torna não mais (e não menos) do que a disciplina de construir linguagens descritivas apropriadas.</p><p>Agora embarcamos em uma viagem pela tecnologia pela qual as linguagens são estabelecidas em termos de outras linguagens. Neste capítulo, usaremos o Lisp como base, implementando avaliadores como procedimentos do Lisp. O <a name="%_idx_4202" id="%_idx_4202"/>Lisp é particularmente adequado para esta tarefa, devido à sua capacidade de representar e manipular expressões simbólicas. Daremos o primeiro passo para entender como as linguagens são implementadas criando um avaliador para o próprio Lisp. A linguagem implementada por nosso avaliador será um subconjunto do dialeto Scheme do Lisp que usamos neste livro. Embora o avaliador descrito neste capítulo tenha sido escrito para um dialeto específico do Lisp, ele contém a estrutura essencial de um avaliador para qualquer linguagem orientada a expressões projetada para escrever programas para uma máquina sequencial. (De fato, a maioria dos processadores de linguagem contém, no fundo, um pequeno avaliador “Lisp”). O avaliador foi simplificado para fins de ilustração e discussão, e foram deixados de fora alguns recursos que seriam importantes para incluir em uma produção sistema Lisp de alta qualidade. No entanto, esse avaliador simples é adequado para executar a maioria dos programas deste livro.<a name="call_footnote_Temp_509" href="#footnote_Temp_509" id="call_footnote_Temp_509"><sup><small>2</small></sup></a></p><p>Uma vantagem importante de tornar o avaliador acessível como um programa Lisp é que podemos implementar regras de avaliação alternativas, descrevendo-as como modificações no programa do avaliador. Um lugar em que podemos usar esse poder com bons resultados é obter um controle extra sobre as maneiras pelas quais os modelos computacionais incorporam a noção de tempo, que foi tão central na discussão no capítulo 3. Lá, mitigamos algumas das complexidades de estado e atribuição usando fluxos para dissociar a representação do tempo no mundo e do tempo no computador. Nossos programas de fluxo, no entanto, às vezes eram pesados, pois eram limitados pela avaliação do Scheme por ordem aplicativa. Na seção <a href="book-Z-H-27.html#%_sec_4.2">4.2</a>, alteraremos a linguagem subjacente para fornecer uma abordagem mais elegante, modificando o avaliador para fornecer <em>avaliação de ordem normal</em>.</p><p>A seção <a href="book-Z-H-28.html#%_sec_4.3">4.3</a> implementa uma mudança linguística mais ambiciosa, na qual as expressões possuem muitos valores, em vez de apenas um único valor. Nesta linguagem da <em>computação não determinística</em>, é natural expressar processos que geram todos os valores possíveis para expressões e, em seguida, procurar por esses valores que satisfazem certas restrições. Em termos de modelos de computação e tempo, é como ter o tempo ramificado em um conjunto de “futuros possíveis” e, em seguida, procurar linhas de tempo apropriadas. Com o nosso avaliador não determinístico, o controle de vários valores e a realização de pesquisas são manipulados automaticamente pelo mecanismo subjacente da linguagem.</p><p>Na seção <a href="book-Z-H-29.html#%_sec_4.4">4.4</a>, implementamos uma linguagem de <em>programação lógica</em> na qual o conhecimento é expresso em termos de relações, e não em termos de cálculos com entradas e saídas. Mesmo que isso torne a linguagem drasticamente diferente do Lisp, ou mesmo de qualquer linguagem convencional, veremos que o avaliador de programação lógica compartilha a estrutura essencial do avaliador do Lisp.</p><p>
</p><p/><div class="smallprint"><hr/></div><p>
</p><div class="footnote"><p><a name="footnote_Temp_508" href="#call_footnote_Temp_508" id="footnote_Temp_508"><sup><small>1</small></sup></a> A mesma ideia é difundida em toda a engenharia. Por exemplo, engenheiros elétricos usam muitas linguagens diferentes para descrever circuitos. Dois deles são a linguagem das <em>redes elétricas</em> e a linguagem dos <em>sistemas elétricos</em>. A linguagem da rede enfatiza a modelagem física de dispositivos em termos de elementos elétricos discretos. Os objetos primitivos da linguagem de rede são componentes elétricos primitivos, como resistores, capacitores, indutores e transistores, que são caracterizados em termos de variáveis físicas chamadas tensão e corrente. Ao descrever circuitos na linguagem de rede, o engenheiro se preocupa com as características físicas de um projeto. Por outro lado, os objetos primitivos da linguagem do sistema são módulos de processamento de sinais, como filtros e amplificadores. Somente o comportamento funcional dos módulos é relevante e os sinais são manipulados sem preocupação com a realização física como tensões e correntes. A linguagem do sistema é montada na linguagem da rede, no sentido de que os elementos dos sistemas de processamento de sinal são construídos a partir de redes elétricas. Aqui, no entanto, as preocupações estão com a organização em larga escala de dispositivos elétricos para resolver um determinado problema de aplicação; a viabilidade física das partes é assumida. Esta coleção de linguagens em camadas é outro exemplo da técnica de projeto estratificada ilustrada pela linguagem de imagens da seção <a href="book-Z-H-15.html#%_sec_2.2.4">2.2.4</a>.</p><p><a name="footnote_Temp_509" href="#call_footnote_Temp_509" id="footnote_Temp_509"><sup><small>2</small></sup></a> Os recursos mais importantes que nosso avaliador deixa de fora são mecanismos para lidar com erros e oferecer suporte à depuração. Para uma discussão mais ampla dos avaliadores, consulte <a name="%_idx_4204" id="%_idx_4204"/><a name="%_idx_4206" id="%_idx_4206"/><a name="%_idx_4208" id="%_idx_4208"/>Friedman, Wand e Haynes 1992, que fornece uma exposição das linguagens de programação que prosseguem por meio de uma sequência de avaliadores escritos em Scheme.</p></div>
</body>
</html>