From a829c647c34d227ef474be49f89be694bc1d8229 Mon Sep 17 00:00:00 2001 From: Rafael Fontenelle Date: Fri, 14 Oct 2022 15:46:30 -0300 Subject: [PATCH 1/3] =?UTF-8?q?Corrige=20erros=20de=20escrita=20e=20adicio?= =?UTF-8?q?na=20entradas=20ao=20dicion=C3=A1rio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/wordlist.txt | 5 +++-- 01/1.0.md | 22 +++++++++++----------- 01/1.1.1.md | 2 +- 01/1.1.4.md | 2 +- 01/1.1.5.md | 2 +- 01/1.1.md | 2 +- 01/1.3.4.md | 22 +++++++++++----------- CONTRIBUTING.md | 2 +- 8 files changed, 30 insertions(+), 29 deletions(-) diff --git a/.github/wordlist.txt b/.github/wordlist.txt index 873b7ca..9555218 100644 --- a/.github/wordlist.txt +++ b/.github/wordlist.txt @@ -33,7 +33,7 @@ JScript JavaScript Jay John -Jr. +Jr Just-In-Time Kleene Landin @@ -110,6 +110,7 @@ não-inteiros of org png +primalidade pt-br script scripts @@ -129,4 +130,4 @@ www align alt code -conduct \ No newline at end of file +conduct diff --git a/01/1.0.md b/01/1.0.md index d214993..6ffae4e 100644 --- a/01/1.0.md +++ b/01/1.0.md @@ -3,26 +3,26 @@ >Os atos da mente pelos quais exerce a sua ação sobre as ideias simples são fundamentalmente estes três: 1. A combinação, numa ideia composta, de várias ideias simples. 2. A segunda é unir duas ideias, sejam estas simples ou complexas, para pô-las uma cerca da outra, sem reduzi-las a uma, pelo qual se chega aos relacionamentos entre ideias. 3. A terceira é a separação de todas as demais ideias que acompanham uma ideia na sua existência real: essa é a chamada abstração, pela qual a mente obtém todas as ideias gerais. > — John Locke, Um ensaio sobre o entendimento humano (1690) -Estamos prestes a estudar a ideia de um _processo t._. Processos computacionais são seres abstratos que habitam computadores. Enquanto evoluem, processos manipulam outras coisas abstratas chamadas _dados_. A evolução de um processo é guiada por um padrão de regras chamado de _programa_. Em efeito, nós cojuramos os espíritos do computador com nossos feitiços. +Estamos prestes a estudar a ideia de um _processo t._. Processos computacionais são seres abstratos que habitam computadores. Enquanto evoluem, processos manipulam outras coisas abstratas chamadas _dados_. A evolução de um processo é guiada por um padrão de regras chamado de _programa_. Em efeito, nós conjuramos os espíritos do computador com nossos feitiços. -Um processo computacional é na verdade muito parecido com a ideia de um espírito de um feiticeiro. Não pode ser visto ou tocado. Não é composto por nenhuma matéria. Entretanto, é bem real. Pode realizar trabalho intelectual. Pode responder perguntas. Pode afetar o mundo ao retirar dinheiro de um banco ou ao controlar um braço robótico em uma fábrica. Os programas que usamos para conjurar processos são como os feitiços do feiticeiro. São expressões simbólicas cuidadosamente compostas em arcanas e esotéricas liguagens de programação que descrevem as tarefas que queremos que nossos processos realizem. +Um processo computacional é na verdade muito parecido com a ideia de um espírito de um feiticeiro. Não pode ser visto ou tocado. Não é composto por nenhuma matéria. Entretanto, é bem real. Pode realizar trabalho intelectual. Pode responder perguntas. Pode afetar o mundo ao retirar dinheiro de um banco ou ao controlar um braço robótico em uma fábrica. Os programas que usamos para conjurar processos são como os feitiços do feiticeiro. São expressões simbólicas cuidadosamente compostas em arcanas e esotéricas linguagens de programação que descrevem as tarefas que queremos que nossos processos realizem. -Um processo computacional, em um computador funcionando corretamente, executa os programas com precisão e acurácia. Assim, como o aprendiz de feiticeiro, programadores iniciantes devem aprender a entender e antecipar as consequencias de suas conjurações. Mesmo erros pequenos (geralmente chamados _bugs_ ou _glitches_) em programas podem ter consequências complexas e não antecipadas. +Um processo computacional, em um computador funcionando corretamente, executa os programas com precisão e acurácia. Assim, como o aprendiz de feiticeiro, programadores iniciantes devem aprender a entender e antecipar as consequências de suas conjurações. Mesmo erros pequenos (geralmente chamados _bugs_ ou _glitches_) em programas podem ter consequências complexas e não antecipadas. -Felizmente, apreder a programar é cosideravelmente menos perigoso do que feitiçaria, pois os espíritos que lidamos estão convenientemente contidos de uma forma segura. Programação no mundo real, entretanto, requer cuidado, conhecimento, e sabedoria. Um pequeno _bug_ na criação de um programa para controle por computador, pode por exemplo, levar à catastrófica colapso de um avião ou uma represa ou a auto-destruição de um robô industrial. +Felizmente, aprender a programar é consideravelmente menos perigoso do que feitiçaria, pois os espíritos que lidamos estão convenientemente contidos de uma forma segura. Programação no mundo real, entretanto, requer cuidado, conhecimento, e sabedoria. Um pequeno _bug_ na criação de um programa para controle por computador, pode por exemplo, levar à catastrófica colapso de um avião ou uma represa ou a autodestruição de um robô industrial. -Engenheiros de software mestres possuem a habilidade de organizar programas de forma que eles possam estar seguramente certos de que os processos resultantes irão realizar as tarefas intencionadas. Visualizam o comportamento de seus sistemas com antecedência. Sabem como estruturar programas para qye problemas não antecipados não levem a consequêcias catastróficas, e quando os problemas surgirem, eles possam _debugar_ seus programas. Sistemas computacionais bem planejados, como automóveis ou reatores nuclares bem planejados, são criados de forma modular, assim as partes podem ser construídas, substituídas, e _debugadas_ separadamente. +Engenheiros de software mestres possuem a habilidade de organizar programas de forma que eles possam estar seguramente certos de que os processos resultantes irão realizar as tarefas intencionadas. Visualizam o comportamento de seus sistemas com antecedência. Sabem como estruturar programas para que problemas não antecipados não levem a consequências catastróficas, e quando os problemas surgirem, eles possam depurar seus programas. Sistemas computacionais bem planejados, como automóveis ou reatores nucleares bem planejados, são criados de forma modular, assim as partes podem ser construídas, substituídas, e depuradas separadamente. ## Programando em JavaScript -Nós precisamos de uma linguagem apropriada para descrever processos, e iremos utilizar para este propósito a linguagem de programação JavaScript. Assim como nossos pensamentos do dia a dia são geralmente expressos em nossa linguagem natural (como Inglês, Francês, Japonês ou o Português), e descrições de fenômenos quantitativos são expressados com equações matemáticas, nossos pensamentos procedurais serão expressos em JavaScript. JavaScript foi desenvolvida no início dos anos 1990 como uma linguagem de programação para controlae os nevagefores da World Wide Web através de _scripts_ incorporados nas páginas da web. A linguagem foi concebida por Brendan Eich, originalmente com o nome Mocha, que depois foi renomeada para LiveScript e finalmente para JavaScript. O nome JavaScript é uma marca registrada da Oracle Corporation. +Nós precisamos de uma linguagem apropriada para descrever processos, e iremos utilizar para este propósito a linguagem de programação JavaScript. Assim como nossos pensamentos do dia a dia são geralmente expressos em nossa linguagem natural (como Inglês, Francês, Japonês ou o Português), e descrições de fenômenos quantitativos são expressados com equações matemáticas, nossos pensamentos procedurais serão expressos em JavaScript. JavaScript foi desenvolvida no início dos anos 1990 como uma linguagem de programação para controlar os navegadores da World Wide Web através de _scripts_ incorporados nas páginas da web. A linguagem foi concebida por Brendan Eich, originalmente com o nome Mocha, que depois foi renomeada para LiveScript e finalmente para JavaScript. O nome JavaScript é uma marca registrada da Oracle Corporation. -A despeito de sua origem como uma liguagem de _script_ para web, JavaScript é uma linnguagem de programação de propósito geral. Um interpretador JavaScript é uma máquina que realiza os processos descritos na linguagem JavaScript. O primeiro interpretador JavaScript foi implementado por Eich na Netscape Communications Corporation, para o navegador da web Netscape Navigator. +A despeito de sua origem como uma linguagem de _script_ para web, JavaScript é uma linguagem de programação de propósito geral. Um interpretador JavaScript é uma máquina que realiza os processos descritos na linguagem JavaScript. O primeiro interpretador JavaScript foi implementado por Eich na Netscape Communications Corporation, para o navegador da web Netscape Navigator. -JavaScript herdou suas características das linguagens de programação Schema e Self. Scheme é um dialeto de Lisp. e foi usada como a linguagem de programação para a versão original deste livro. Do Scheme, JavaScript herdou seus mais fundamentais princípios de design como funções de primeira classe escopadas lexicalmentte e tipagem dinâmica. +JavaScript herdou suas características das linguagens de programação Schema e Self. Scheme é um dialeto de Lisp. e foi usada como a linguagem de programação para a versão original deste livro. Do Scheme, JavaScript herdou seus mais fundamentais princípios de design como funções de primeira classe com escopo lexical e tipagem dinâmica. -JavaScript possui apenas aparência superficial com a linguagem Java, após a qual foi (eventualmente) batizada; tanto Java e JavaScript usam a estrutura de bloco da linguagem C. Em contraste com Java e C, as quais geralmente utilizam compilação para linguagens de baixo nível, programas JavaScript foram inicialmente interpretados pelos navegadores da web. Após o Netscape Navigator, outros navegadores web proveram interpretadores para a linguagem incluindo o Internet Explorer da Microsof, cuja versão do JavaScript foi nomeada JScript. A popularidade do JavaScript para controlar navegadores web culiminou em um esforço para sua padronização, culminando no ECMAScript. A primeira edição do padrão foi liderada por Guy Lewis Steele Jr. e completada em Junho de 1997 (ECMA 1997). A sexta edição, conhecida como ECMAScript 2015, foi liderada por Allen Wirfs-Brock e adotada pela Assembléia Geral da ECMA em Junho de 2015 (ECMA 2015). +JavaScript possui apenas aparência superficial com a linguagem Java, após a qual foi (eventualmente) batizada; tanto Java e JavaScript usam a estrutura de bloco da linguagem C. Em contraste com Java e C, as quais geralmente utilizam compilação para linguagens de baixo nível, programas JavaScript foram inicialmente interpretados pelos navegadores da web. Após o Netscape Navigator, outros navegadores web proveram interpretadores para a linguagem incluindo o Internet Explorer da Microsoft, cuja versão do JavaScript foi nomeada JScript. A popularidade do JavaScript para controlar navegadores web culminou em um esforço para sua padronização, culminando no ECMAScript. A primeira edição do padrão foi liderada por Guy Lewis Steele Jr. e completada em Junho de 1997 (ECMA 1997). A sexta edição, conhecida como ECMAScript 2015, foi liderada por Allen Wirfs-Brock e adotada pela Assembleia Geral da ECMA em Junho de 2015 (ECMA 2015). -A prática de incorporar programas JavaScript em páginas da web encorajou os desenvolvedores de nevagedores web a implementarem interpretadores JavaScript. Assim que foram se tornando mais complexos, esses interpretadores se tornaram mais eficientes em executá-los, eventualmente utilizando implementações sofisticadas como compilação Just-In-Time (JIT). A maioria dos programas JavaScript no momento em que é escrito (2021) são incorporados em páginas da web e interpretados por navegadores, mas JavaScript é cada vez mais utilizada como uma linguagem de programação com propósito geral, usando sistemas com o o Node.js. +A prática de incorporar programas JavaScript em páginas da web encorajou os desenvolvedores de navegadores web a implementarem interpretadores JavaScript. Assim que foram se tornando mais complexos, esses interpretadores se tornaram mais eficientes em executá-los, eventualmente utilizando implementações sofisticadas como compilação Just-In-Time (JIT). A maioria dos programas JavaScript no momento em que é escrito (2021) são incorporados em páginas da web e interpretados por navegadores, mas JavaScript é cada vez mais utilizada como uma linguagem de programação com propósito geral, usando sistemas com o o Node.js. -Entretanto, é a habilidade dos navegadores de executar programas JavaScript que tornam uma linguagem ideal para uma versão online sobre programas de computador. Executar programas ao clicar nas coisas em uma página da web é natural em JavaScript - afinal é exatamente o que JavaScript foi criado para fazer! Mais fundamentalmentte, ECMAScript 2015 possui um conjunto de características que o ttornam um excelenete meio para esttudar importante construtos de programação e estruturas de dados e para relacioná-los com as características linguísticas que os suportam. Suas funções de primeira classe escopadas lexicalmente e seu suporte sintatico através de expressões lambda proveem um acesso direto e conciso para a abstração funcional, e a tipagem dinâmica nos permitem adaptar para se manter próximo ao Scheme originalmente utilizado ao longo do livro. E ainda mais, além de todas estas considerações, programar em JavaScript é uma grande diversão. +Entretanto, é a habilidade dos navegadores de executar programas JavaScript que tornam uma linguagem ideal para uma versão online sobre programas de computador. Executar programas ao clicar nas coisas em uma página da web é natural em JavaScript - afinal é exatamente o que JavaScript foi criado para fazer! Mais fundamentalmente, ECMAScript 2015 possui um conjunto de características que o tornam um excelente meio para estudar importante construtos de programação e estruturas de dados e para relacioná-los com as características linguísticas que os suportam. Suas funções de primeira classe com escopo lexical e seu suporte sintático através de expressões lambda proveem um acesso direto e conciso para a abstração funcional, e a tipagem dinâmica nos permitem adaptar para se manter próximo ao Scheme originalmente utilizado ao longo do livro. E ainda mais, além de todas estas considerações, programar em JavaScript é uma grande diversão. diff --git a/01/1.1.1.md b/01/1.1.1.md index 2bb2ad5..903dc94 100644 --- a/01/1.1.1.md +++ b/01/1.1.1.md @@ -12,7 +12,7 @@ Um tipo de instrução que você pode digitar é uma instrução de *expressão* clicando nela, ele responderá exibindo um interpretador JavaScript com a opção de avaliar a instrução pressionando um botão "Run" (Executar). Clique na instrução da expressão primitiva e veja o que acontece! -Expressões que representam números podem ser combinadas com operadores (como + ou \*) para formar uma expressão composta que representa a aplicação de uma função primitiva correspondente a esses números. Por exemplo, avalie qualquer uma das seguintes instrções de expressão clicando nela: +Expressões que representam números podem ser combinadas com operadores (como + ou \*) para formar uma expressão composta que representa a aplicação de uma função primitiva correspondente a esses números. Por exemplo, avalie qualquer uma das seguintes instruções de expressão clicando nela: ```js 137 + 349; diff --git a/01/1.1.4.md b/01/1.1.4.md index d051cd3..7b50c51 100644 --- a/01/1.1.4.md +++ b/01/1.1.4.md @@ -115,6 +115,6 @@ Além de funções compostas, qualquer ambiente JavaScript fornece funções pri [[3]](#footnote-link-3) De maneira mais geral, o corpo da função pode ser uma sequência de instruções. Nesse caso, o interpretador avalia cada instrução na sequência sucessivamente até que uma instrução de retorno determine o valor da aplicação da função. - [[4]](#footnote-link-4) A maneira como os nomes de várias partes, como `sum_of_squares`, são escritos, afeta a legibilidade dos programas, e as comunidades de programação diferem nisso. De acordo com a convenção do JavaScript comum, chamada *camel case*, o nome seria `sumOfSquares`. A convenção usada neste livro é chamada de *snake case* e foi escolhida por sua maior semelhança com a convenção usada na versão Scheme deste livro, onde hífens desempenham o papel de nossos sublinhados. + [[4]](#footnote-link-4) A maneira como os nomes de várias partes, como `sum_of_squares`, são escritos, afeta a legibilidade dos programas, e as comunidades de programação diferem nisso. De acordo com a convenção do JavaScript comum, chamada *camel case*, o nome seria `sumOfSquares`. A convenção usada neste livro é chamada de *snake case* e foi escolhida por sua maior semelhança com a convenção usada na versão Scheme deste livro, onde hífenes desempenham o papel de nossos sublinhados. [[5]](#footnote-link-5) Nosso ambiente JavaScript inclui todas as funções e constantes do [objeto Math](https://www.ecma-international.org/ecma-262/9.0/index.html#sec-math-object) do ECMAScript, sob os nomes `math_…`. Por exemplo, o `Math.log` do ECMAScript está disponível como `math_log`. A página da web do MIT Press para este livro inclui o pacote JavaScript `sicp` que fornece essas e todas as outras funções JavaScript consideradas primitivas no livro. diff --git a/01/1.1.5.md b/01/1.1.5.md index 22941b6..483024b 100644 --- a/01/1.1.5.md +++ b/01/1.1.5.md @@ -57,7 +57,7 @@ iria proceder de acordo com a sequência de expansões `(5 + 1) * (5 + 1) + (5 * 2) * (5 * 2)` -Seguido pelas reduçoes: +Seguido pelas reduções: ``` 6 * 6 + 10 * 10 diff --git a/01/1.1.md b/01/1.1.md index b5abe27..e674dd4 100644 --- a/01/1.1.md +++ b/01/1.1.md @@ -1,6 +1,6 @@ # 1.1 Os Elementos da Programação -Uma linguagem poderosa de programação é mais do que apenas um meio para instruir o computador a realizar tarefas. A linguagem também serve como um framework no qual nós podemos organizar nossas ideias sobre processos. Assim, quando nós descrevemos uma limguagem, devemos ter atenção particular para as formas que a linguagem provê para combinar ideias simples para formar ideias mais complexas. Toda linguagem poderosa possui três mecanismos para atingir isto: +Uma linguagem poderosa de programação é mais do que apenas um meio para instruir o computador a realizar tarefas. A linguagem também serve como um framework no qual nós podemos organizar nossas ideias sobre processos. Assim, quando nós descrevemos uma linguagem, devemos ter atenção particular para as formas que a linguagem provê para combinar ideias simples para formar ideias mais complexas. Toda linguagem poderosa possui três mecanismos para atingir isto: - **expressões primitivas**, as quais representam as entidades mais simples que a linguagem está interessada, - **meios de combinação**, pelas quais elementos compostos são construídos de outros mais simples, e diff --git a/01/1.3.4.md b/01/1.3.4.md index 4f4a683..d77d9e3 100644 --- a/01/1.3.4.md +++ b/01/1.3.4.md @@ -2,7 +2,7 @@ Os exemplos abaixo demonstram como a habilidade de ter funções como argumentos melhora significativamente o poder da expressão de nossas linguagens de computação. Nos podemos alcançar ainda mais poder expressivo criando funções que tem seu retorno também sendo funções. -Nos podemos ilustrar essa ideia olhando de novo para o exemplo de ponto fixo descrito no final da sessão 1.3.3. Nos formulamos uma nova versão da função de raiz quadrada como uma busca de ponto fixo, começando com a observação que $\sqrt{x}$ é um ponto fixo da função $y \mapsto{x/y}$. Então nos usamos um amortecimento médio para fazer as aproximações convergirem. Amortecimento médio é uma técnica bem util no geral. Dada uma função $f$, nos consideramos a função a qual o valor em $x$ é igual ao média de $x$ e $f(x)$. +Nos podemos ilustrar essa ideia olhando de novo para o exemplo de ponto fixo descrito no final da sessão 1.3.3. Nos formulamos uma nova versão da função de raiz quadrada como uma busca de ponto fixo, começando com a observação que $\sqrt{x}$ é um ponto fixo da função $y \mapsto{x/y}$. Então nos usamos um amortecimento médio para fazer as aproximações convergirem. Amortecimento médio é uma técnica bem útil no geral. Dada uma função $f$, nos consideramos a função a qual o valor em $x$ é igual ao média de $x$ e $f(x)$. Nos podemos expressar a ideia do amortecimento médio pela seguinte função: @@ -44,7 +44,7 @@ $f(x) = x - \frac{g(x)}{Dg(x)}$ E $Dg(x)$ é a derivada de $g$ calculada em $x$. O método de Newton faz uso do ponto fixo como vimos acima para aproximar uma solução da equação encontrando um ponto fixo da função $f$ [3](#footnote-link-3). Para muitas funções $g$ e para suposições iniciais suficientemente boas para $x$. O método de Newton converge muito rapidamente para uma solução de $g(x) = 0$.[4](#footnote-link-4) -Para implementar o método de Newton como uma função, primeiro devemos expressas a ideia de uma derivada. Note que "derivada", como um amortecimento médio, é algo que transforma a função em outra função, por exemplo, a derivada da função $x \mapsto{x^3}$ e a função $x \mapsto{3x^2}$. No geral, se $g$ é uma função e $dx$ é um número pequeno, então a derivada $Dg$ de $g$ é a função a qual o valor em qualquer número $x$ pe dado (no limite do pequeno $dx$) por: +Para implementar o método de Newton como uma função, primeiro devemos expressas a ideia de uma derivada. Note que "derivada", como um amortecimento médio, é algo que transforma a função em outra função, por exemplo, a derivada da função $x \mapsto{x^3}$ e a função $x \mapsto{3x^2}$. No geral, se $g$ é uma função e $dx$ é um número pequeno, então a derivada $Dg$ de $g$ é a função a qual o valor em qualquer número $x$ é dado (no limite do pequeno $dx$) por: $Dg(x) = \frac{g(x+dx)-g(x)}{dx}$ @@ -94,7 +94,7 @@ function sqrt(x) { ## Abstrações e funções de primeira classe -Nos vemos duas maneiras para expressas a computação da raiz quadrada, como uma instância mais geral do método, uma com uma busca de ponto fixo e outra utilizando o método de Newton que foi expresso como um processo de ponto fixo, na verdade nos imos duas maneiras de computar raízes quadradas como pontos fixos. Cada método começa com uma função e acha um ponto fixo de alguma transformação da função. Nos podemos expressar a ideia geral como sendo a função: +Nos vemos duas maneiras para expressas a computação da raiz quadrada, como uma instância mais geral do método, uma com uma busca de ponto fixo e outra utilizando o método de Newton que foi expresso como um processo de ponto fixo, na verdade nós vimos duas maneiras de computar raízes quadradas como pontos fixos. Cada método começa com uma função e acha um ponto fixo de alguma transformação da função. Nos podemos expressar a ideia geral como sendo a função: ```js function fixed_point_of_transform(g, transform, guess) { @@ -115,7 +115,7 @@ functnon sqrt(x) { } ``` -De maneira similar, nos podemos expressar a segunda maneira de computar a raiz quadrada dessa seção (a que instanciámos o método de Newton que acha um ponto fixo pela transformada de Newton da função $y \mapsto{y^2 -x}$) como: +De maneira similar, nos podemos expressar a segunda maneira de computar a raiz quadrada dessa seção (a que instanciamos o método de Newton que acha um ponto fixo pela transformada de Newton da função $y \mapsto{y^2 -x}$) como: ```js function sqrt(x) { @@ -126,18 +126,18 @@ function sqrt(x) { } ``` -Nós começamos a seção 1.3 com a observação que funções compostas são um mecanismo de abstração crucial, porque eles permitem que possamos expressas métodos gerais de computação como elementos explícitos na linguagem de programação. Agora nós vimos como funções de ordem-maior permitem que nós possamos manipular esses métodos para criar ainda mais abstrações. +Nós começamos a seção 1.3 com a observação que funções compostas são um mecanismo de abstração crucial, porque eles permitem que possamos expressas métodos gerais de computação como elementos explícitos na linguagem de programação. Agora nós vimos como funções de ordem maior permitem que nós possamos manipular esses métodos para criar ainda mais abstrações. -Como programadores, nós devemos ficar alerta a oportunidades para identificar abstrações subjacentes nos nossos programas e construir elas para generaliza-las afim que criar abstrações mais poderosas. Isso não quer dizer que você sempre deve escrever programas da maneira mais abstrata possível; programadores experientes sabem como escolher o nível de abstração apropriado para cada tarefa. Porém é importante ser capaz de pensar in termos dessas abstrações, então temos que estar preparados para aplicar elas em novos contextos. A importância de funções de ordem-maior é que elas permites que nos possamos representar essas abstrações explicitamente como elementos de nossa linguagem de programação, para que elas possam ser manipuladas como qualquer outro elemento computacional. +Como programadores, nós devemos ficar alerta a oportunidades para identificar abstrações subjacentes nos nossos programas e construir elas para generalizá-las afim que criar abstrações mais poderosas. Isso não quer dizer que você sempre deve escrever programas da maneira mais abstrata possível; programadores experientes sabem como escolher o nível de abstração apropriado para cada tarefa. Porém é importante ser capaz de pensar in termos dessas abstrações, então temos que estar preparados para aplicar elas em novos contextos. A importância de funções de ordem maior é que elas permites que nos possamos representar essas abstrações explicitamente como elementos de nossa linguagem de programação, para que elas possam ser manipuladas como qualquer outro elemento computacional. -No geral, linguagens de programação impõem restrições na maneira com o que os elementos computacionais podem ser manipulados. Elemento com menores restrições são ditos como tendo status de *primeira-classe*. Alguns dos "direitos e privilégios" dos elementos de primeira-classe são:[6](#footnote-link-6) +No geral, linguagens de programação impõem restrições na maneira com o que os elementos computacionais podem ser manipulados. Elemento com menores restrições são ditos como tendo status de *primeira classe*. Alguns dos "direitos e privilégios" dos elementos de primeira classe são:[6](#footnote-link-6) - Eles podem ser chamados por nomes. - Eles podem ser passados como argumentos para funções. - Eles podem ser retornado como resultado de funções - Eles podem ser incluídos em estruturas de dados.[7](#footnote-link-7) -Javascript, como qualquer outra linguagem de programação de alto-nível, considera funções como elementos de primeira-classe. Isso desafia implementações mais eficientes, mas o ganho em expressividade é enorme.[8](#footnote-link-8) +JavaScript, como qualquer outra linguagem de programação de alto nível, considera funções como elementos de primeira classe. Isso desafia implementações mais eficientes, mas o ganho em expressividade é enorme.[8](#footnote-link-8) ---- @@ -147,12 +147,12 @@ Javascript, como qualquer outra linguagem de programação de alto-nível, consi [3] Livros de cálculo elementar geralmente descrevem o método de Newton em termos da sequência de aproximações $x_{n+1} = x_{n} - g(x_{n})/Dg(x_{n})$. Ter uma linguagem para falar sobre esses processos e usar a ideia de pontos fixos, simplifica a descrição desse método. - [4] O método de Newton nem sempre converge para uma resposta, mas é mostrado que em casos favoráveis cada iteração a acurácia da aproximação da solução dobra. O método de Newton vai convergir muito mais rapidamente que o método da Bissecção. + [4] O método de Newton nem sempre converge para uma resposta, mas é mostrado que em casos favoráveis cada iteração a acurácia da aproximação da solução dobra. O método de Newton vai convergir muito mais rapidamente que o método da Bisseção. [5] Para achar raízes quadradas, o método de Newton converge rapidamente para a solução de qualquer ponto de partida. - [6] A notação de status de primeira-classe de elementos de linguagem de programação vem do cientista de computação britânico Christopher Strachey (1916-1975) + [6] A notação de status de primeira classe de elementos de linguagem de programação vem do cientista de computação britânico Christopher Strachey (1916-1975) [7] Nos vamos ver exemplos que introduzem estruturas de dados no capitulo 2. - [8] O maior custo de implementação de funções de primeira-classe é que permitir funções serem retornadas como valor requer reservar armazenamento para uma função, ter espaço livre e nome livres ate mesmo enquanto a função não esta executando. Em JavaScript a implementação nos vamos estudar na seção 4.1, essas funções e seus nomes são armazenadas no escopo da função de maior-ordem. + [8] O maior custo de implementação de funções de primeira classe é que permitir funções serem retornadas como valor requer reservar armazenamento para uma função, ter espaço livre e nome livres ate mesmo enquanto a função não esta executando. Em JavaScript a implementação nos vamos estudar na seção 4.1, essas funções e seus nomes são armazenadas no escopo da função de maior-ordem. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2547db1..225af7b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,7 +3,7 @@ ## Nossa promessa -Como pessoas participantes, colaboradoras e líderes, nós nos comprometemos a fazer com que a participação em nossa comunidade seja uma experiência livre de assédio para todas as pessoas, independentemente de idade, tamanho do corpo, deficiência aparente ou não aparente, etnia, características sexuais, identidade ou expressão de gênero, nível de experiência, educação, situação sócio-econômica, nacionalidade, aparência pessoal, raça, religião ou identidade e orientação sexuais. +Como pessoas participantes, colaboradoras e líderes, nós nos comprometemos a fazer com que a participação em nossa comunidade seja uma experiência livre de assédio para todas as pessoas, independentemente de idade, tamanho do corpo, deficiência aparente ou não aparente, etnia, características sexuais, identidade ou expressão de gênero, nível de experiência, educação, situação socioeconômica, nacionalidade, aparência pessoal, raça, religião ou identidade e orientação sexuais. Comprometemo-nos a agir e interagir de maneiras que contribuam para uma comunidade aberta, acolhedora, diversificada, inclusiva e saudável. From ff960c51e0ceebeb23ec84b7200c1565a2022ec0 Mon Sep 17 00:00:00 2001 From: Rafael Fontenelle Date: Fri, 14 Oct 2022 16:32:42 -0300 Subject: [PATCH 2/3] =?UTF-8?q?Corrige=20viola=C3=A7=C3=B5es=20de=20regras?= =?UTF-8?q?=20relatadas=20pelo=20markdownlinter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 01/1.1.1.md | 6 ++---- 01/1.1.3.md | 4 ++-- 01/1.1.4.md | 23 +++++++++-------------- 01/1.1.5.md | 20 +++++++++----------- 01/1.1.8.md | 17 ++++++++--------- 5 files changed, 30 insertions(+), 40 deletions(-) diff --git a/01/1.1.1.md b/01/1.1.1.md index 903dc94..e63c257 100644 --- a/01/1.1.1.md +++ b/01/1.1.1.md @@ -96,8 +96,6 @@ que o interpretador avaliaria prontamente como sendo 57. Podemos nos ajudar escr para separar visualmente os principais componentes da expressão. -Mesmo com expressões complexas, o interpretador sempre opera no mesmo ciclo básico: ele lê uma instrução digitada pelo usuário, avalia a instrução e imprime o resultado. Este modo de operação é frequentemente expresso dizendo que o interpretador é executado em um *loop de leitura-avaliação-impressão* (também conhecido como REPL). Observe em particular que não é necessário instruir explicitamente o interpretador a imprimir o valor da instrução.[1](#footnote-1) +Mesmo com expressões complexas, o interpretador sempre opera no mesmo ciclo básico: ele lê uma instrução digitada pelo usuário, avalia a instrução e imprime o resultado. Este modo de operação é frequentemente expresso dizendo que o interpretador é executado em um *loop de leitura-avaliação-impressão* (também conhecido como REPL). Observe em particular que não é necessário instruir explicitamente o interpretador a imprimir o valor da instrução.[^1] ------ - - [1] O JavaScript obedece à convenção de que cada instrução tem um valor (consulte o exercício [4.8](4.1.2#ex-4.8)). Essa convenção, junto com a reputação dos programadores JavaScript de não se preocuparem com a eficiência, nos leva a parafrasear uma piada sobre os programadores Lisp de Alan Perlis (que estava parafraseando Oscar Wilde): *Os programadores JavaScript sabem o valor de tudo, mas o custo de nada.* +[^1]: O JavaScript obedece à convenção de que cada instrução tem um valor (consulte o exercício [4.8](4.1.2#ex-4.8)). Essa convenção, junto com a reputação dos programadores JavaScript de não se preocuparem com a eficiência, nos leva a parafrasear uma piada sobre os programadores Lisp de Alan Perlis (que estava parafraseando Oscar Wilde): *Os programadores JavaScript sabem o valor de tudo, mas o custo de nada.* diff --git a/01/1.1.3.md b/01/1.1.3.md index 6701f35..cee82a7 100644 --- a/01/1.1.3.md +++ b/01/1.1.3.md @@ -16,8 +16,8 @@ Observe como a ideia de recursão pode ser usada sucintamente para expressar o q requer que a regra de avaliação seja aplicada a quatro combinações diferentes. Podemos obter uma imagem desse processo representando a combinação na forma de uma árvore, conforme mostrado na figura [1.1](#fig-1.1). Cada combinação é representada por um nó com ramificações correspondentes ao operador e aos operandos da combinação que dele decorrem. Os nós terminais (ou seja, nós sem ramificações derivadas deles) representam operadores ou números. Vendo a avaliação em termos de árvore, podemos imaginar que os valores dos operandos percolam para cima, começando nos nós terminais e depois combinando em níveis cada vez mais altos. Em geral, veremos que a recursão é uma técnica muito poderosa para lidar com objetos hierárquicos semelhantes a árvores. Na verdade, a forma de "filtrar os valores para cima" da regra de avaliação é um exemplo de um tipo geral de processo conhecido como `acumulação de árvore`. - -![#fig-1.1](https://sicp.sourceacademy.org/img_javascript/ch1-Z-G-1.svg) + +![fig-1.1](https://sicp.sourceacademy.org/img_javascript/ch1-Z-G-1.svg) Figura 1.1 Representação em árvore, mostrando o valor de cada subexpressão. diff --git a/01/1.1.4.md b/01/1.1.4.md index 7b50c51..e8894a3 100644 --- a/01/1.1.4.md +++ b/01/1.1.4.md @@ -25,15 +25,13 @@ function square( x ) { return x * x; } // perfeito ``` - -Temos aqui uma *função composta*, que recebeu o nome `square`. A função representa a operação de multiplicação de algo por si mesmo. A coisa a ser multiplicada recebe um nome local, `x`, que desempenha o mesmo papel que um pronome na linguagem natural. A avaliação da declaração cria esta função composta e a associa ao nome `square`.[1](#footnote-1) +Temos aqui uma *função composta*, que recebeu o nome `square`. A função representa a operação de multiplicação de algo por si mesmo. A coisa a ser multiplicada recebe um nome local, `x`, que desempenha o mesmo papel que um pronome na linguagem natural. A avaliação da declaração cria esta função composta e a associa ao nome `square`.[^1] A forma mais simples de declaração de uma função é function *nome*(*parâmetros*) { return *expressão*; } - -O *nome* é um símbolo a ser associado à definição da função no ambiente.[2](#footnote-2) Os *parâmetros* são os nomes usados no corpo da função para se referir aos argumentos correspondentes da função. Os *parâmetros* são agrupados entre parênteses e separados por vírgulas, pois estarão em uma aplicação da função que está sendo declarada. Na forma mais simples, o *corpo* de uma declaração de função é uma única *instrução de retorno*[3](#footnote-3), que consiste na palavra-chave return seguida pela *expressão de retorno* que produzirá o valor da aplicação da função, quando os parâmetros são substituídos pelos argumentos reais para os quais a função é aplicada. Como as declarações constantes e as declarações de expressão, as declarações de retorno terminam com um caractere de ponto e vírgula. +O *nome* é um símbolo a ser associado à definição da função no ambiente.[^2] Os *parâmetros* são os nomes usados no corpo da função para se referir aos argumentos correspondentes da função. Os *parâmetros* são agrupados entre parênteses e separados por vírgulas, pois estarão em uma aplicação da função que está sendo declarada. Na forma mais simples, o *corpo* de uma declaração de função é uma única *instrução de retorno*[^3], que consiste na palavra-chave return seguida pela *expressão de retorno* que produzirá o valor da aplicação da função, quando os parâmetros são substituídos pelos argumentos reais para os quais a função é aplicada. Como as declarações constantes e as declarações de expressão, as declarações de retorno terminam com um caractere de ponto e vírgula. Tendo declarado `square`, agora podemos usá-lo em uma expressão de *aplicação de função*, que transformamos em uma instrução usando um caractere de ponto e vírgula: @@ -75,8 +73,7 @@ Também podemos usar a `square` como um bloco de construção na definição de square(x) + square(y) ``` - -Podemos facilmente declarar uma função `sum_of_squares`[4](#footnote-4) que, dados quaisquer dois números como argumentos, produz a soma de seus quadrados: +Podemos facilmente declarar uma função `sum_of_squares`[^4] que, dados quaisquer dois números como argumentos, produz a soma de seus quadrados: ```js function sum_of_squares(x, y) { @@ -104,17 +101,15 @@ f(5); 136 - -Além de funções compostas, qualquer ambiente JavaScript fornece funções primitivas que estão embutidas no interpretador ou carregadas de bibliotecas. Além das funções primitivas fornecidas pelos operadores, o ambiente JavaScript usado neste livro inclui funções primitivas adicionais, como a função `math_log`, que calcula o logaritmo natural de seu argumento.[5](#footnote-5) Essas funções primitivas adicionais são usadas exatamente da mesma maneira que as funções compostas; avaliar a aplicação `math_log(1)` resulta no número 0. De fato, não se poderia dizer olhando para a definição de `sum_of_squares` dada acima se ``square` foi embutida no interpretador, carregado de uma biblioteca ou definido como uma função composta. +Além de funções compostas, qualquer ambiente JavaScript fornece funções primitivas que estão embutidas no interpretador ou carregadas de bibliotecas. Além das funções primitivas fornecidas pelos operadores, o ambiente JavaScript usado neste livro inclui funções primitivas adicionais, como a função `math_log`, que calcula o logaritmo natural de seu argumento.[^5] Essas funções primitivas adicionais são usadas exatamente da mesma maneira que as funções compostas; avaliar a aplicação `math_log(1)` resulta no número 0. De fato, não se poderia dizer olhando para a definição de `sum_of_squares` dada acima se ``square` foi embutida no interpretador, carregado de uma biblioteca ou definido como uma função composta. ----- - [[1]](#footnote-link-1) Observe que há duas operações diferentes sendo combinadas aqui: estamos criando a função e estamos dando a ela o nome `square`. É possível, de fato importante, ser capaz de separar essas duas noções – criar funções sem nomeá-las e dar nomes a funções que já foram criadas. Veremos como fazer isso na seção [1.3.2](1.3.2.md). +[^1]: Observe que há duas operações diferentes sendo combinadas aqui: estamos criando a função e estamos dando a ela o nome `square`. É possível, de fato importante, ser capaz de separar essas duas noções – criar funções sem nomeá-las e dar nomes a funções que já foram criadas. Veremos como fazer isso na seção [1.3.2](1.3.2.md). - [[2]](#footnote-link-2) Ao longo deste livro, descreveremos a sintaxe geral das expressões usando símbolos em itálico – por exemplo, nome – para denotar os "slots" na expressão a ser preenchida quando tal expressão for realmente usada. +[^2]: Ao longo deste livro, descreveremos a sintaxe geral das expressões usando símbolos em itálico – por exemplo, nome – para denotar os "slots" na expressão a ser preenchida quando tal expressão for realmente usada. - [[3]](#footnote-link-3) De maneira mais geral, o corpo da função pode ser uma sequência de instruções. Nesse caso, o interpretador avalia cada instrução na sequência sucessivamente até que uma instrução de retorno determine o valor da aplicação da função. +[^3]: De maneira mais geral, o corpo da função pode ser uma sequência de instruções. Nesse caso, o interpretador avalia cada instrução na sequência sucessivamente até que uma instrução de retorno determine o valor da aplicação da função. - [[4]](#footnote-link-4) A maneira como os nomes de várias partes, como `sum_of_squares`, são escritos, afeta a legibilidade dos programas, e as comunidades de programação diferem nisso. De acordo com a convenção do JavaScript comum, chamada *camel case*, o nome seria `sumOfSquares`. A convenção usada neste livro é chamada de *snake case* e foi escolhida por sua maior semelhança com a convenção usada na versão Scheme deste livro, onde hífenes desempenham o papel de nossos sublinhados. +[^4]: A maneira como os nomes de várias partes, como `sum_of_squares`, são escritos, afeta a legibilidade dos programas, e as comunidades de programação diferem nisso. De acordo com a convenção do JavaScript comum, chamada *camel case*, o nome seria `sumOfSquares`. A convenção usada neste livro é chamada de *snake case* e foi escolhida por sua maior semelhança com a convenção usada na versão Scheme deste livro, onde hífenes desempenham o papel de nossos sublinhados. - [[5]](#footnote-link-5) Nosso ambiente JavaScript inclui todas as funções e constantes do [objeto Math](https://www.ecma-international.org/ecma-262/9.0/index.html#sec-math-object) do ECMAScript, sob os nomes `math_…`. Por exemplo, o `Math.log` do ECMAScript está disponível como `math_log`. A página da web do MIT Press para este livro inclui o pacote JavaScript `sicp` que fornece essas e todas as outras funções JavaScript consideradas primitivas no livro. +[^5] Nosso ambiente JavaScript inclui todas as funções e constantes do [objeto Math](https://www.ecma-international.org/ecma-262/9.0/index.html#sec-math-object) do ECMAScript, sob os nomes `math_…`. Por exemplo, o `Math.log` do ECMAScript está disponível como `math_log`. A página da web do MIT Press para este livro inclui o pacote JavaScript `sicp` que fornece essas e todas as outras funções JavaScript consideradas primitivas no livro. diff --git a/01/1.1.5.md b/01/1.1.5.md index 483024b..dcb4b2b 100644 --- a/01/1.1.5.md +++ b/01/1.1.5.md @@ -4,8 +4,7 @@ Para avaliar uma aplicação de função, o interpretador segue o processo descr Podemos assumir que a aplicação de funções primitivas é feita pelo interpretador ou bibliotecas. Para funções compostas, o processo de aplicação é o seguinte: - -- Para aplicar uma função composta a argumentos, avalie a expressão de retorno da função com cada parâmetro substituído pelo argumento correspondente.[1](#footnote-1) +- Para aplicar uma função composta a argumentos, avalie a expressão de retorno da função com cada parâmetro substituído pelo argumento correspondente.[^1] Para ilustrar esse processo, vamos avaliar a aplicação @@ -40,8 +39,8 @@ e finalmente para: O processo que acabamos de descrever é chamado de `modelo de substituição` para aplicação de função. Pode ser tomado como um modelo que determina o "significado" da aplicação da função, no que diz respeito às funções neste capítulo. No entanto, há dois pontos que devem ser destacados: - O objetivo da substituição é nos ajudar a pensar sobre a aplicação da função, não fornecer uma descrição de como o interpretador realmente funciona. Os interpretadores típicos não avaliam os aplicações de função manipulando o texto de uma função para substituir os valores dos parâmetros. Na prática, a "substituição" é realizada usando um ambiente local para os parâmetros. Discutiremos isso mais detalhadamente nos capítulos 3 e 4, quando examinarmos a implementação de um interpretador em detalhes. - -- Ao longo deste livro, apresentaremos uma sequência de modelos cada vez mais elaborados de como os interpretadores funcionam, culminando com uma implementação completa de um interpretador e compilador no capítulo [5](5.0.md). O modelo de substituição é apenas o primeiro desses modelos - uma maneira de comece a pensar formalmente sobre o processo de avaliação. Em geral, ao modelar fenômenos em ciência e engenharia, começamos com modelos simplificados e incompletos. À medida que examinamos as coisas com mais detalhes, esses modelos simples tornam-se inadequados e devem ser substituídos por modelos mais refinados. O modelo de substituição não é exceção. Em particular, quando abordamos no capítulo 3 o uso de funções com "dados mutáveis", veremos que o modelo de substituição falha e deve ser substituído por um modelo mais complicado de aplicação de função.[2](#footnote-2) + +- Ao longo deste livro, apresentaremos uma sequência de modelos cada vez mais elaborados de como os interpretadores funcionam, culminando com uma implementação completa de um interpretador e compilador no capítulo [5](5.0.md). O modelo de substituição é apenas o primeiro desses modelos - uma maneira de comece a pensar formalmente sobre o processo de avaliação. Em geral, ao modelar fenômenos em ciência e engenharia, começamos com modelos simplificados e incompletos. À medida que examinamos as coisas com mais detalhes, esses modelos simples tornam-se inadequados e devem ser substituídos por modelos mais refinados. O modelo de substituição não é exceção. Em particular, quando abordamos no capítulo 3 o uso de funções com "dados mutáveis", veremos que o modelo de substituição falha e deve ser substituído por um modelo mais complicado de aplicação de função.[^2] ## Ordem aplicativa vs. ordem normal @@ -59,7 +58,7 @@ iria proceder de acordo com a sequência de expansões Seguido pelas reduções: -``` +```text 6 * 6 + 10 * 10 36 + 100 @@ -74,13 +73,12 @@ Isso dá a mesma resposta que nosso modelo de avaliação anterior, mas o proces com x substituído respectivamente por _5 + 1_ e _5 \* 2_. Este método de avaliação alternativo "expandir totalmente e então reduzir" é conhecido como avaliação de ordem normal, em contraste com o método de "avaliar os argumentos e depois aplicar" que o interpretador realmente usa, que é chamado de *avaliação de ordem de aplicação*. Pode-se mostrar que, para aplicações de função que podem ser modelados usando substituição (incluindo todas as funções nos primeiros dois capítulos deste livro) e que geram valores legítimos, a avaliação de ordem normal e de ordem de aplicação produzem o mesmo valor. (Consulte o exercício [1.5](1.5.md) para obter uma instância de um valor "ilegítimo" em que a avaliação da ordem normal e da ordem aplicativa não dá o mesmo resultado.) - -JavaScript usa avaliação de ordem de aplicação, em parte por causa da eficiência adicional obtida ao evitar avaliações múltiplas de expressões como aquelas ilustradas com _5 + 1_ e _5 \* 2_ acima e, mais significativamente, porque a avaliação de ordem normal se torna muito mais complicada de lidar quando deixamos o reino das funções que podem ser modeladas por substituição. Por outro lado, a avaliação de ordem normal pode ser uma ferramenta extremamente valiosa, e investigaremos algumas de suas implicações nos capítulos [3] e [4].[3](#footnote-3) ---- +JavaScript usa avaliação de ordem de aplicação, em parte por causa da eficiência adicional obtida ao evitar avaliações múltiplas de expressões como aquelas ilustradas com _5 + 1_ e _5 \* 2_ acima e, mais significativamente, porque a avaliação de ordem normal se torna muito mais complicada de lidar quando deixamos o reino das funções que podem ser modeladas por substituição. Por outro lado, a avaliação de ordem normal pode ser uma ferramenta extremamente valiosa, e investigaremos algumas de suas implicações nos capítulos 3 e 4.[^3] + - [[1]](#footnote-link-1) Se o corpo da função for uma sequência de instruções, o corpo será avaliado com os parâmetros substituídos e o valor da aplicação será o valor da expressão de retorno da primeira instrução de retorno encontrada. +[^1]: Se o corpo da função for uma sequência de instruções, o corpo será avaliado com os parâmetros substituídos e o valor da aplicação será o valor da expressão de retorno da primeira instrução de retorno encontrada. - [[2]](#footnote-link-2) Apesar da simplicidade da ideia de substituição, é surpreendentemente complicado dar uma definição matemática rigorosa do processo de substituição. O problema surge da possibilidade de confusão entre os nomes usados para os parâmetros de uma função e os nomes (possivelmente idênticos) usados nas expressões às quais a função pode ser aplicada. Na verdade, há uma longa história de definições errôneas de substituição na literatura de lógica e semântica de programação. Veja Stoy 1977 para uma discussão cuidadosa sobre substituição. +[^2]: Apesar da simplicidade da ideia de substituição, é surpreendentemente complicado dar uma definição matemática rigorosa do processo de substituição. O problema surge da possibilidade de confusão entre os nomes usados para os parâmetros de uma função e os nomes (possivelmente idênticos) usados nas expressões às quais a função pode ser aplicada. Na verdade, há uma longa história de definições errôneas de substituição na literatura de lógica e semântica de programação. Veja Stoy 1977 para uma discussão cuidadosa sobre substituição. - [[3]](#footnote-link-3) No capítulo [3], apresentaremos o processamento de fluxo, que é uma maneira de lidar com estruturas de dados aparentemente "infinitas", incorporando uma forma limitada de avaliação de ordem normal. Na seção [4.2], modificaremos o interpretador JavaScript para produzir uma variante de ordem normal do JavaScript. +[^3]: No capítulo 3, apresentaremos o processamento de fluxo, que é uma maneira de lidar com estruturas de dados aparentemente "infinitas", incorporando uma forma limitada de avaliação de ordem normal. Na seção [4.2](4.2.md), modificaremos o interpretador JavaScript para produzir uma variante de ordem normal do JavaScript. diff --git a/01/1.1.8.md b/01/1.1.8.md index 6cb52ba..77ff4d1 100644 --- a/01/1.1.8.md +++ b/01/1.1.8.md @@ -11,7 +11,7 @@ Figura 1.1 Representação em árvore, mostrando o valor de cada subexpressão. A importância dessa estratégia de decomposição não é simplesmente que se divida o programa em partes. Afinal, poderíamos pegar qualquer programa grande e dividi-lo em partes - as primeiras dez linhas, as próximas dez linhas, as próximas dez linhas e assim por diante. Em vez disso, é crucial que cada função realize uma tarefa identificável que pode ser usada como um módulo na definição de outras funções. Por exemplo, quando definimos a função `is_good_enough` em termos de `square`, podemos considerar a função `square` como uma "caixa preta". Não estamos, naquele momento, preocupados com a forma como a função calcula seu resultado, apenas com o fato de que ela calcula o `square`. Os detalhes de como o `square` é calculado podem ser suprimidos para serem considerados em um momento posterior. Na verdade, no que diz respeito à função `is_good_enough`, o `square` não é exatamente uma função, mas sim uma abstração de uma função, uma assim chamada abstração funcional. Nesse nível de abstração, qualquer função que calcule o `square` é igualmente boa. -Assim, considerando apenas os valores que eles retornam, as duas funções a seguir que elevam ao `square` um número devem ser indistinguíveis. Cada um recebe um argumento numérico e produz o `square` desse número como o valor.[1](#footnote-1) +Assim, considerando apenas os valores que eles retornam, as duas funções a seguir que elevam ao `square` um número devem ser indistinguíveis. Cada um recebe um argumento numérico e produz o `square` desse número como o valor.[^1] ```js function square(x) { @@ -66,7 +66,7 @@ A intenção do autor de `is_good_enough` é determinar se o `square` do primeir Se os parâmetros não fossem locais para os corpos de suas respectivas funções, o parâmetro x no `square` poderia ser confundido com o parâmetro x em is_good_enough, e o comportamento de is_good_enough dependeria de qual versão do `square` usamos. Portanto, o `square` não seria a caixa preta que desejamos. -Um parâmetro de uma função tem um papel muito especial na declaração da função, pois não importa o nome do parâmetro. Esse nome é chamado de _bound_ (vinculado) e dizemos que a declaração da função _binds_ (vincula) seus parâmetros. O significado de uma declaração de função permanece inalterado se um nome vinculado for consistentemente renomeado em toda a declaração.[2](#footnote-2) Se um nome não for vinculado, dizemos que ele é gratuito. O conjunto de instruções para as quais uma ligação declara um nome é chamado de escopo desse nome. Em uma declaração de função, os nomes vinculados declarados como os parâmetros da função têm o corpo da função como seu escopo. +Um parâmetro de uma função tem um papel muito especial na declaração da função, pois não importa o nome do parâmetro. Esse nome é chamado de _bound_ (vinculado) e dizemos que a declaração da função _binds_ (vincula) seus parâmetros. O significado de uma declaração de função permanece inalterado se um nome vinculado for consistentemente renomeado em toda a declaração.[^2] Se um nome não for vinculado, dizemos que ele é gratuito. O conjunto de instruções para as quais uma ligação declara um nome é chamado de escopo desse nome. Em uma declaração de função, os nomes vinculados declarados como os parâmetros da função têm o corpo da função como seu escopo. Na declaração de `is_good_enough` acima, `guess` e x são nomes vinculados, mas `abs` e `square` são livres. O significado de `is_good_enough` deve ser independente dos nomes que escolhemos para a `guess` e x, desde que sejam distintos e diferentes de `abs` e `square`. (Se renomearmos `guess` para `abs`, teríamos introduzido um _bug_ ao capturar o nome `abs`. Ele teria mudado de _free_ para _bound_.) O significado de `is_good_enough` não é independente da escolha de seus nomes livres, entretanto. Certamente depende do fato (externo a esta declaração) de que o nome `abs` se refere a uma função para calcular o valor absoluto de um número. A função `is_good_enough` computará uma função diferente se substituirmos `math_cos` (a função cosseno primitiva) por `abs` em sua declaração. @@ -110,7 +110,7 @@ function sqrt(x) { sqrt(5); ``` -Qualquer par de chaves correspondente designa um bloco e as declarações dentro do bloco são locais para o bloco. Esse aninhamento de declarações, chamado de estrutura de bloco, é basicamente a solução certa para o problema mais simples de empacotamento de nomes. Mas existe uma ideia melhor escondida aqui. Além de internalizar as declarações das funções auxiliares, podemos simplificá-las. Como x está vinculado à declaração de `sqrt`, as funções `is_good_enough`, `improve` e `sqrt_iter`, que são declaradas internamente como `tosqrt`, estão no escopo de x. Portanto, não é necessário passar x explicitamente para cada uma dessas funções. Em vez disso, permitimos que x seja um nome livre nas declarações internas, conforme mostrado abaixo. Então x obtém seu valor do argumento com o qual a função envolvente `sqrt` é chamada. Esta disciplina é chamada de _escopo léxico_.[3](#footnote-3) +Qualquer par de chaves correspondente designa um bloco e as declarações dentro do bloco são locais para o bloco. Esse aninhamento de declarações, chamado de estrutura de bloco, é basicamente a solução certa para o problema mais simples de empacotamento de nomes. Mas existe uma ideia melhor escondida aqui. Além de internalizar as declarações das funções auxiliares, podemos simplificá-las. Como x está vinculado à declaração de `sqrt`, as funções `is_good_enough`, `improve` e `sqrt_iter`, que são declaradas internamente como `tosqrt`, estão no escopo de x. Portanto, não é necessário passar x explicitamente para cada uma dessas funções. Em vez disso, permitimos que x seja um nome livre nas declarações internas, conforme mostrado abaixo. Então x obtém seu valor do argumento com o qual a função envolvente `sqrt` é chamada. Esta disciplina é chamada de _escopo léxico_.[^3] ```js function sqrt(x) { @@ -129,14 +129,13 @@ function sqrt(x) { sqrt(5); ``` -Usaremos a estrutura de blocos extensivamente para nos ajudar a quebrar grandes programas em partes tratáveis.[4](#footnote-4) A ideia da estrutura de blocos originou-se com a linguagem de programação Algol 60. Ela aparece na maioria das linguagens de programação avançadas e é uma ferramenta importante para ajudar a organizar a construção de grandes programas. +Usaremos a estrutura de blocos extensivamente para nos ajudar a quebrar grandes programas em partes tratáveis.[^4] A ideia da estrutura de blocos originou-se com a linguagem de programação Algol 60. Ela aparece na maioria das linguagens de programação avançadas e é uma ferramenta importante para ajudar a organizar a construção de grandes programas. ---- - [[1]](#footnote-link-1) Ainda não está claro qual dessas funções é uma implementação mais eficiente. Isso depende do hardware disponível. Existem máquinas para as quais a implementação "óbvia" é a menos eficiente. Considere uma máquina que possui extensas tabelas de logaritmos e antilogaritmos armazenados de uma maneira muito eficiente. +[^1]: Ainda não está claro qual dessas funções é uma implementação mais eficiente. Isso depende do hardware disponível. Existem máquinas para as quais a implementação "óbvia" é a menos eficiente. Considere uma máquina que possui extensas tabelas de logaritmos e antilogaritmos armazenados de uma maneira muito eficiente. - [[2]](#footnote-link-2) O conceito de renomeação consistente é realmente sutil e difícil de definir formalmente. Lógicos famosos cometeram erros embaraçosos aqui. +[^2]: O conceito de renomeação consistente é realmente sutil e difícil de definir formalmente. Lógicos famosos cometeram erros embaraçosos aqui. - [[3]](#footnote-link-3) O escopo léxico dita que nomes livres em uma função são considerados como referências a associações feitas por declarações de função inclusas; ou seja, eles são pesquisados no ambiente em que a função foi declarada. Veremos como isso funciona em detalhes no capítulo 3, quando estudarmos os ambientes e o comportamento detalhado do interpretador. +[^3]: O escopo léxico dita que nomes livres em uma função são considerados como referências a associações feitas por declarações de função inclusas; ou seja, eles são pesquisados no ambiente em que a função foi declarada. Veremos como isso funciona em detalhes no capítulo 3, quando estudarmos os ambientes e o comportamento detalhado do interpretador. - [[4]](#footnote-link-4) As declarações incorporadas devem vir primeiro em um corpo de função. A gerência não se responsabiliza pelas consequências da execução de programas que entrelaçam declaração e uso; ver também notas de rodapé [2] e [4] na seção [1.3.2](1.3.2.md). +[^4]: As declarações incorporadas devem vir primeiro em um corpo de função. A gerência não se responsabiliza pelas consequências da execução de programas que entrelaçam declaração e uso; ver também notas de rodapé [^2] e [^4] na seção [1.3.2](1.3.2.md). From b11e4b088b9ea084b3822d4e1b289579fcf3b68a Mon Sep 17 00:00:00 2001 From: Rafael Fontenelle Date: Sat, 15 Oct 2022 22:09:55 -0300 Subject: [PATCH 3/3] =?UTF-8?q?Corrige=20mais=20viola=C3=A7=C3=B5es=20de?= =?UTF-8?q?=20regras=20do=20markdownlinter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/wordlist.txt | 1 + 01/1.1.4.md | 1 - 01/1.1.5.md | 3 +-- 01/1.1.8.md | 1 - 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/wordlist.txt b/.github/wordlist.txt index 9555218..75b3d3a 100644 --- a/.github/wordlist.txt +++ b/.github/wordlist.txt @@ -46,6 +46,7 @@ MIT Martin Marvin McCarthy +Microsoft Minsky Mozilla Navigator diff --git a/01/1.1.4.md b/01/1.1.4.md index e8894a3..aaf3e4b 100644 --- a/01/1.1.4.md +++ b/01/1.1.4.md @@ -103,7 +103,6 @@ f(5); Além de funções compostas, qualquer ambiente JavaScript fornece funções primitivas que estão embutidas no interpretador ou carregadas de bibliotecas. Além das funções primitivas fornecidas pelos operadores, o ambiente JavaScript usado neste livro inclui funções primitivas adicionais, como a função `math_log`, que calcula o logaritmo natural de seu argumento.[^5] Essas funções primitivas adicionais são usadas exatamente da mesma maneira que as funções compostas; avaliar a aplicação `math_log(1)` resulta no número 0. De fato, não se poderia dizer olhando para a definição de `sum_of_squares` dada acima se ``square` foi embutida no interpretador, carregado de uma biblioteca ou definido como uma função composta. - [^1]: Observe que há duas operações diferentes sendo combinadas aqui: estamos criando a função e estamos dando a ela o nome `square`. É possível, de fato importante, ser capaz de separar essas duas noções – criar funções sem nomeá-las e dar nomes a funções que já foram criadas. Veremos como fazer isso na seção [1.3.2](1.3.2.md). [^2]: Ao longo deste livro, descreveremos a sintaxe geral das expressões usando símbolos em itálico – por exemplo, nome – para denotar os "slots" na expressão a ser preenchida quando tal expressão for realmente usada. diff --git a/01/1.1.5.md b/01/1.1.5.md index dcb4b2b..1bcd400 100644 --- a/01/1.1.5.md +++ b/01/1.1.5.md @@ -72,11 +72,10 @@ Isso dá a mesma resposta que nosso modelo de avaliação anterior, mas o proces com x substituído respectivamente por _5 + 1_ e _5 \* 2_. -Este método de avaliação alternativo "expandir totalmente e então reduzir" é conhecido como avaliação de ordem normal, em contraste com o método de "avaliar os argumentos e depois aplicar" que o interpretador realmente usa, que é chamado de *avaliação de ordem de aplicação*. Pode-se mostrar que, para aplicações de função que podem ser modelados usando substituição (incluindo todas as funções nos primeiros dois capítulos deste livro) e que geram valores legítimos, a avaliação de ordem normal e de ordem de aplicação produzem o mesmo valor. (Consulte o exercício [1.5](1.5.md) para obter uma instância de um valor "ilegítimo" em que a avaliação da ordem normal e da ordem aplicativa não dá o mesmo resultado.) +Este método de avaliação alternativo "expandir totalmente e então reduzir" é conhecido como avaliação de ordem normal, em contraste com o método de "avaliar os argumentos e depois aplicar" que o interpretador realmente usa, que é chamado de _avaliação de ordem de aplicação_. Pode-se mostrar que, para aplicações de função que podem ser modelados usando substituição (incluindo todas as funções nos primeiros dois capítulos deste livro) e que geram valores legítimos, a avaliação de ordem normal e de ordem de aplicação produzem o mesmo valor. (Consulte o exercício [1.5](1.5.md) para obter uma instância de um valor "ilegítimo" em que a avaliação da ordem normal e da ordem aplicativa não dá o mesmo resultado.) JavaScript usa avaliação de ordem de aplicação, em parte por causa da eficiência adicional obtida ao evitar avaliações múltiplas de expressões como aquelas ilustradas com _5 + 1_ e _5 \* 2_ acima e, mais significativamente, porque a avaliação de ordem normal se torna muito mais complicada de lidar quando deixamos o reino das funções que podem ser modeladas por substituição. Por outro lado, a avaliação de ordem normal pode ser uma ferramenta extremamente valiosa, e investigaremos algumas de suas implicações nos capítulos 3 e 4.[^3] - [^1]: Se o corpo da função for uma sequência de instruções, o corpo será avaliado com os parâmetros substituídos e o valor da aplicação será o valor da expressão de retorno da primeira instrução de retorno encontrada. [^2]: Apesar da simplicidade da ideia de substituição, é surpreendentemente complicado dar uma definição matemática rigorosa do processo de substituição. O problema surge da possibilidade de confusão entre os nomes usados para os parâmetros de uma função e os nomes (possivelmente idênticos) usados nas expressões às quais a função pode ser aplicada. Na verdade, há uma longa história de definições errôneas de substituição na literatura de lógica e semântica de programação. Veja Stoy 1977 para uma discussão cuidadosa sobre substituição. diff --git a/01/1.1.8.md b/01/1.1.8.md index 77ff4d1..2c891f1 100644 --- a/01/1.1.8.md +++ b/01/1.1.8.md @@ -131,7 +131,6 @@ sqrt(5); Usaremos a estrutura de blocos extensivamente para nos ajudar a quebrar grandes programas em partes tratáveis.[^4] A ideia da estrutura de blocos originou-se com a linguagem de programação Algol 60. Ela aparece na maioria das linguagens de programação avançadas e é uma ferramenta importante para ajudar a organizar a construção de grandes programas. - [^1]: Ainda não está claro qual dessas funções é uma implementação mais eficiente. Isso depende do hardware disponível. Existem máquinas para as quais a implementação "óbvia" é a menos eficiente. Considere uma máquina que possui extensas tabelas de logaritmos e antilogaritmos armazenados de uma maneira muito eficiente. [^2]: O conceito de renomeação consistente é realmente sutil e difícil de definir formalmente. Lógicos famosos cometeram erros embaraçosos aqui.