2.1.1 Exemplo: Operações Aritméticas para Números Racionais
Suponha que queremos fazer aritmética com números racionais. Queremos ser capazes de adicioná-los, subtraí-los, multiplicá-los e dividi-los, e testar se dois números racionais são iguais.
Vamos começar assumindo que já temos uma maneira de construir um número racional a partir de um numerador e um denominador. Também assumimos que, dado um número racional, temos uma maneira de extrair (ou selecionar) seu numerador e seu denominador. Vamos supor ainda que o construtor e os seletores estão disponíveis como funções:
make_rat(n, d)retorna o número racional cujo numerador é o inteiro n e cujo denominador é o inteiro d.numer(x)retorna o numerador do número racional x.denom(x)retorna o denominador do número racional x.
Estamos usando aqui uma estratégia poderosa de síntese: wishful thinking (pensamento positivo). Ainda não dissemos como um número racional é representado, ou como as funções numer, denom e make_rat devem ser implementadas. Mesmo assim, se tivéssemos essas três funções, poderíamos então adicionar, subtrair, multiplicar, dividir e testar a igualdade usando as seguintes relações:
Podemos expressar essas regras como funções:
Carregando playground de código...
Agora temos as operações em números racionais definidas em termos das funções seletoras e construtoras numer, denom e make_rat. Mas ainda não definimos essas funções. O que precisamos é de alguma maneira de colar um numerador e um denominador para formar um número racional.
Pares
Para nos permitir implementar o nível concreto de nossa abstração de dados, nosso ambiente JavaScript fornece uma estrutura composta chamada par (pair), que pode ser construída com a função primitiva pair. Esta função recebe dois argumentos e retorna um objeto de dados composto que contém os dois argumentos como partes. Dado um par, podemos extrair as partes usando as funções primitivas head e tail. Assim, podemos usar pair, head e tail da seguinte forma:
Carregando playground de código...
Carregando playground de código...
Observe que um par é um objeto de dados que pode receber um nome e ser manipulado, assim como um objeto de dados primitivo. Além disso, pair pode ser usado para formar pares cujos elementos são pares, e assim por diante:
Carregando playground de código...
Carregando playground de código...
Na seção 2.2 veremos como essa capacidade de combinar pares significa que os pares podem ser usados como blocos de construção de propósito geral para criar todos os tipos de estruturas de dados complexas. O único primitivo de dados compostos par, implementado pelas funções pair, head e tail, é a única cola que precisamos. Objetos de dados construídos a partir de pares são chamados de dados estruturados em lista.
Representando números racionais
Os pares oferecem uma maneira natural de completar o sistema de números racionais. Simplesmente representamos um número racional como um par de dois inteiros: um numerador e um denominador. Então make_rat, numer e denom são prontamente implementados da seguinte forma:
Carregando playground de código...
Além disso, para exibir os resultados de nossos cálculos, podemos imprimir números racionais imprimindo o numerador, uma barra e o denominador. Usamos a função primitiva stringify para transformar qualquer valor (aqui um número) em uma string. O operador + em JavaScript é sobrecarregado; ele pode ser aplicado a dois números ou a duas strings, e no último caso ele retorna o resultado de concatenar as duas strings.
Carregando playground de código...
Agora podemos experimentar nossas funções de números racionais:
Carregando playground de código...
Carregando playground de código...
Carregando playground de código...
Como o exemplo final mostra, nossa implementação de números racionais não reduz os números racionais aos menores termos. Podemos remediar isso mudando make_rat. Se tivermos uma função gcd como a da seção 1.2.5 que produz o maior divisor comum de dois inteiros, podemos usar gcd para reduzir o numerador e o denominador aos menores termos antes de construir o par:
Carregando playground de código...
Agora temos o resultado desejado. Esta modificação foi realizada mudando o construtor make_rat sem mudar nenhuma das funções (como add_rat e mul_rat) que implementam as operações reais.
Exercício 2.1
Defina uma versão melhor de make_rat que lida com argumentos positivos e negativos. A função make_rat deve normalizar o sinal de modo que, se o número racional for positivo, tanto o numerador quanto o denominador sejam positivos, e se o número racional for negativo, apenas o numerador seja negativo.
Carregando playground de código...
📝 Encontrou algo errado nesta página?
Sua ajuda é muito importante para melhorar a qualidade da tradução!
🐛 Encontrou um erro?
Se você encontrou:
- Erro de tradução (palavra incorreta, termo técnico errado)
- Erro de ortografia ou gramática
- Link quebrado
- Código de exemplo que não funciona
- Problema de formatação
❓ Tem uma dúvida?
Se você tem:
- Dúvida sobre o conteúdo desta seção
- Pergunta sobre um conceito do SICP
- Dificuldade em entender algum exemplo
- Questão sobre a tradução de algum termo
💡 Tem uma sugestão de melhoria?
Se você quer sugerir:
- Melhoria na explicação
- Exemplo adicional
- Recurso visual (diagrama, ilustração)
- Qualquer outra ideia
🌍 Quer discutir a tradução?
Se você quer debater:
- Escolha de tradução de algum termo
- Consistência de terminologia
- Nuances do português
Obrigado por ajudar a melhorar o SICP.js PT-BR! ✨