Buscar

Paradigmas apostila

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 80 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 80 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 80 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

Prof. Kesede R Julio
Apostila de 
Paradigmas de 
Linguagens de Programação
versão: 2011
Prof. Kesede R Julio
Índice
Capítulo 1 Introdução......................................................................................................4
 1.1 Recomendações ao Aluno 4
 1.2 Alguns Aspectos Básicos 4
 1.3 Exercícios 9
Capítulo 2 Paradigma Imperativo....................................................................................9
 2.1 Tipos 9
 2.1.1 Tipos Primitivos 10
 2.1.1 Tipos Compostos 12
 2.1.1 Tipos Recursivos 13
 2.1 Expressões 14
 2.1.1 Operadores Sobrecarregados 17
 2.1.2 Erros em expressões 18
 2.1.3 Expressões Relacionais 18
 2.1.4 Expressões Booleanas 19
 2.1.5 Avaliação Curto-Circuito 19
 2.2 Comandos 20
 2.2.1 Instruções de Atribuição 21
 2.2.1 Instruções Compostas e Blocos 22
 2.2.2 Condicionais 23
 2.2.3 Iterativos 24
 2.2.4 Desvio Incondicional 25
 2.3 Abstrações 26
 2.3.1 Abstração de Processos 26
 2.3.1.1 Funções 27
 2.3.1.1 Procedimentos 28
 2.3.1.2 Parâmetros 28
 2.4 Exemplo de Linguagem: Pascal 30
Capítulo 3 Paradigma Orientado à Objeto.....................................................................33
 3.1 Tipo abstrato de dados 33
 3.2 Herança 39
 3.3 Acoplamento dinâmico 41
 3.4 Polimorfismo 41
 3.5 Exemplo de linguagem: Python 42
 3.5.1 Características 42
Paradigmas de Linguagens de Programação - versão 2011 2
Prof. Kesede R Julio
 3.5.2 Elementos da linguagem 43
Capítulo 4 Paradigma Lógico.........................................................................................50
 4.1Proposições 50
 4.2Forma Clausal 51
 4.3Cálculo de Predicados e Demonstração de Teoremas 52
 4.4Elementos básicos do Prolog 54
 4.5Exemplos de Linguagem: Prolog63
Capítulo 5 Paradigma Funcional...................................................................................69
 5.1 Fundamentos 69
 5.2 Funções Simples 71
 5.3 Forma Funcional 71
 5.4 A Linguagem Scheme 72
 5.4.1 Funções primitivas 72
 5.4.2 Funções que constroem funções 74
 5.4.3 Funções de Predicados 75
 5.4.4 Fluxo de Controle 76
 5.4.5 Exemplos 78
Paradigmas de Linguagens de Programação - versão 2011 3
Prof. Kesede R Julio
 1 Introdução
 1.1 Recomendações ao Aluno
O estudo dos paradigmas de linguagens de programação 
requer dedicação na pesquisa de novas linguagens, e sempre 
formalizando este estudo. O conhecimento dos diferentes paradigmas 
é adquirido através do estudo dos princípios e conceitos que norteiam a 
construção das linguagens. Este tipo de pesquisa dará a você condições 
de definir com maior propriedade qual dos paradigmas utilizar para 
determinada aplicação.
 1.2 Alguns Aspectos Básicos
Programa:- Podemos definir um programa como uma 
máquina abstrata, pois o mesmo produz e manipula entidades 
abstratas (dados). Enquanto documento ele se torna a descrição da 
Paradigmas de Linguagens de Programação - versão 2011 4
Prof. Kesede R Julio
máquina, passando a ser a própria máquina quando em execução. O 
meio físico onde esta máquina é implementada é o computador.
Linguagem de Programação:- Um conjunto de recursos e 
regras capaz de construir máquinas abstratas a serem implementadas 
com qualidade em computadores. A primeira linguagem a ser 
construída chamava-se Plankalkul, desenvolvida em 1945, publicada 
em 1972, porém nunca implementada. Também em meados de 1950, 
deu-se o interesse pela Inteligência Artificial, e com ele uma linguagem 
que pudesse expressar seus problemas e retornar resultados. Uma 
linguagem que pudesse representar dados simbólicos em listas 
encadeadas, pois nesta época, as representações eram de dados 
numéricos em matrizes. Após varias pesquisas e implementações, o 
Lisp foi criado. 
As principais características de uma linguagem de 
programação, são:
Requisitos:- qual universo de problemas queremos resolver?
Expressividade:- melhor forma para representar os elementos 
da linguagem
Paradigma:- qual a forma mais adequada para representar e 
resolver os problemas apresentados por uma determinada aplicação.
Implementação:- o que é passível de implementação
Eficiência:- relação entre custo x benefício da implementação
Sintaxe:- como escrevemos os elementos da linguagem.
Semântica:- o significado de cada elemento da linguagem, ou 
seja, seu comportamento quando em execução.
 
Compiladores e Interpretadores:- Para colocarmos em 
funcionamento uma linguagem, precisamos de um processador de 
linguagem (compilador ou interpretador). Um processador de 
linguagem é um programa capaz de transformar códigos escritos pelo 
Paradigmas de Linguagens de Programação - versão 2011 5
Prof. Kesede R Julio
programador (programa-fonte) em códigos entendidos pelo sistema 
operacional para qual o código foi escrito. Existem ainda alguns 
compiladores que geram códigos para serem lidos por máquinas 
virtuais, deixando assim o programa-fonte independente dos sistemas 
operacionais. Um exemplo disto é o MVJ : Máquina Virtual Java.
Compiladores:- Estes processadores transformam o código 
escrito pelo programador em um código que pode ser lido diretamente 
pelo computador (código de máquina). Uma vez convertido, o 
computador executa, de uma única vez, todo o código de máquina. 
Estes processadores tem como principal característica a velocidade de 
processamento, porém nada é executado se for verificado algum erro 
de sintaxe. A figura abaixo mostra isso com mais detalhes.
Paradigmas de Linguagens de Programação - versão 2011 6
Programa fonte
Analisador Léxico:
constroem os símbolos léxicos (lexical tokens) que são 
os identificadores, palavras reservadas, operadores etc, 
para serem analisados sintaticamente
Analisador Sintático (ou parser)
verifica se símbolos léxicos obedecem as 
regras sintáticas da construção da linguagem, 
construindo assim uma Árvore Sintática da Estrutura 
Analisador Semântico
verifica se há conflitos difíceis/impossíveis de 
serem resolvidos pelo Parser. Ex.: coersão de tipos
Gerador de código de máquina
constroe um código capaz de ser interpretado pela 
CPU do computador (micro-instruções)
Prof. Kesede R Julio
Separado do compilador, temos o linker, que tem a tarefa de 
juntar arquivos pré-compilados (do sistema operacional ou do usuário) 
afim de gerar um único executável.
Interpretadores:- Já nestes processadores, os códigos 
escritos pelo programador é verificado e executado um-a-um, ou seja, 
cada linha é analítica e sintaticamente depurada e imediatamente 
executada pela CPU, caso não se verifique erros. Por isso, programas 
feitos nestes processadores podem executar perfeitamente algumas 
instruções e interromper a execução logo que encontrar um erro. Sua 
grande desvantagem é a lentidão. A figura abaixo mostra o esquema 
de um interpretador.
Metodologia de Programação:- Cada problema requer um 
ponto de vista para ser olhado. As linguagens de programação são 
construídas para dar “amplitude” neste olhar, e assim, resolver 
problemas que antes não puderam ser resolvidos, ou eram resolvidos 
precária e paliativamente. Com o passar dos anos vários paradigmas de 
programação foram sendo desenvolvidos, todos eles pela necessidade 
de resolver problemas que outros paradigmas (olhares) não resolviam. 
Alguns deles, são: 
Paradigmas de Linguagens de Programação - versão2011 7
Código de máquina
Programa-fonte
Interpretador
Código 
executado
Prof. Kesede R Julio
Orientado à Objetos:- Olha para o problema e transforma 
as entidades em objetos (características e funções). Ex.: C++, 
Smalltalk.
Imperativas:- Prioriza as informações (dados) envolvidas no 
problema. Ex.: C, Pascal, Fortran.
Declarativas:- Vê o problema como uma relação das 
declarações (objetos, dados e relações). Especializando este paradigma 
podemos destacar outros dois: Lógica:- as relações são caracterizadas 
pela lógica matemática. Ex.: Prolog, Godel e Funcional:- as relações 
são caracterizadas por mapeamentos entre estruturas simbólicas. Ex.: 
Lisp, Haskell.
 1.3 Exercícios
1.3.1Faça uma pesquisa do histórico das linguagens agrupando-as 
Paradigmas de Linguagens de Programação - versão 2011 8
Prof. Kesede R Julio
em seus respectivos paradigmas.
 2 Paradigma Imperativo
 2.1 Tipos
As informações são elementos fundamentais para o estudo de 
linguagens, uma vez que é por elas que os programas são feitos. As 
informações são caracterizadas por 3 elementos básicos: variáveis, 
tipos e valores.
Variáveis:- Para que as informações sejam guardadas e 
utilizadas em partes diferentes do programa, precisamos definir 
variáveis, que nada mais são que espaços em memória para alocação 
temporária da informação.
Tipos:- Através dos tipos classificamos (agrupamos) as 
informações de acordo com sua natureza. As regras para tratamento 
das informações são definidas de acordo com esta classificação, pois 
caso contrário, teríamos que tratar cada informação individualmente. O 
tipo define não apenas a natureza da informação, como também o 
domínio (valores possíveis) do espaço onde ela será alocada.
Valores:- São representações de um conceito, ou seja, a 
Paradigmas de Linguagens de Programação - versão 2011 9
Prof. Kesede R Julio
representação de um nome de pessoa, de um peso, de uma marca de 
carro etc.
Juntamente com os tipos definimos também as operações que 
serão realizadas sobre eles. Estudaremos os conceitos matemáticos que 
originaram os conceitos de agrupamento e tratamento de tipos. 
Existem 3 tipos de dados básicos que devemos analisar: primitivos, 
compostos e recursivos.
 2.1.1 Tipos Primitivos
Um tipo primitivo é, em si mesmo, atômico, ou seja, não pode 
ser subdividido. Podemos citar alguns tipos conhecidos, como: inteiro, 
booleano, real, caractere, enumerado.
A definição dos tipo de uma linguagem e a forma que serão 
tratados dependerá do domínio de aplicações que a linguagem pretende 
suportar. Linguagens criadas para fins científicos (Ex.: Fortran) tem 
forte apelo aos tipos numéricos de precisão, já linguagens criadas para 
fins comerciais (Ex.: Cobol) tem forte apelo para tipos alfanuméricos. 
O Numéricos se dividem basicamente em dois tipos: inteiro e 
ponto flutuante.
O nome ponto flutuante é utilizado para distinguir a 
representação computacional (limitada pelo hardware) da 
representação matemática (infinita).
Exemplo em Pascal:
val_int: integer;
val_real: real;
Os Não-Numéricos, podem ser: Booleanos, caracteres e 
Paradigmas de Linguagens de Programação - versão 2011 10
Prof. Kesede R Julio
ponteiros.
Os booleanos permitem a representação dos valores 0 e 1. Já 
o tipo caractere permite o agrupamento de símbolos ('A'..'Z', 'a'..'z', 
'0'..'9', ':', ';' etc) e o tipo ponteiro agrupa endereços de memória, afim 
de suportar endereçamento direto pelas linguagens, além de alocação e 
desalocação dinâmica de varáveis.
Exemplo em Pascal:
var
caractere: Character; // variável tipo caractere
booleano: Boolean; // variável tipo boolean
pont_int: ^Integer; // variável tipo ponteiro para inteiro
O tipo Enumerado permite a construção de novos conjuntos 
de dados, além daqueles já contemplados pela matemática, mantendo 
a ordem com que são declarados. Um valor inteiro é associado a cada 
valor da enumeração. 
Exemplo em Pascal:
type
Estacoes = (Verao, Outono, Inverno, Primavera);
Pascal e Modula-2 ainda suporta o tipo intervalo, que também 
é um subconjunto de um tipo primitivo, e portanto, todas as operações 
vinculadas ao tipo é herdada.
Exemplo de Pascal:
type
Meses = 1..12;
 2.1.1 Tipos Compostos
Desta forma podemos construir tipos a partir de outros tipos, 
Paradigmas de Linguagens de Programação - versão 2011 11
Prof. Kesede R Julio
primitivos ou não. Isto é interessante a partir do momento em que 
precisamos agrupar informações diferentes, porem dentro de um 
mesmo contexto. Exemplo: (datas: dia, mês e ano; coordenadas de um 
ponto: x e y; dias possíveis para pagamento de uma conta etc). Assim 
como os tipos primitivos, os tipos compostos também são provenientes 
das leis matemática: produto cartesiano, união disjunta, mapeamentos 
e conjunto potência.
Exemplo em C de Produto Cartesiano:
enum DiasC{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}
enum MesesC{jan,fev,mar,abr,mai,jun,
jul,ago,set,out,nov,dez}
struct DataC{
DiasC d;
MeseC m;
};
Exemplo em C de União Disjunta:
union NumeroC{
int ival;
float rval;
};
Neste exemplo, a variável ival e rval compartilharão do 
mesmo espaço de memória, ou seja, quando um valor é atribuído à 
ival, o valor de rval é sobreposto.
Em programação, os Mapeamentos são feitos através da 
estrutura de vetores, onde o conjunto domínio é denominado de índice 
e o conjunto imagem é o elemento do vetor.
Paradigmas de Linguagens de Programação - versão 2011 12
Prof. Kesede R Julio
Exemplo em Pascal:
Var
tempP:array[1..30] of real;
As funções também podem ser consideradas como 
mapeamento, uma vez que o domínio seria os argumentos de entrada 
e a imagem o retorno da função.
Exemplo em Pascal de Conjunto Potência:
type
Cores = (vermelho, azul, amarelo);
NovasCores = set of Cores;
Neste exemplo o tipo NovasCores tem os seguinte valores: 
{{}, {vermelho}, {azul}, {amarelo}, {vermelho, azul}, {vermelho, 
amarelo}, {azul, amarelo},{vermelho, azul, amarelo}}
A linguagem C não contempla este tipo de conjunto.
 2.1.1 Tipos Recursivos
Um tipo recursivo contém elementos do seu próprio tipo. A 
cardinalidade do conjunto resultante é infinita.
Exemplo em Pascal:
type
IntListP = ^IntNode;
IntNode = record
valor: Integer;
prox: IntListP
end;
Paradigmas de Linguagens de Programação - versão 2011 13
Prof. Kesede R Julio
 2.1 Expressões
Podemos representar valores através de expressões 
aritméticas. A grande maioria das linguagens provê uma série de 
elementos capazes de manipular variáveis oferecendo os mesmos 
recursos da matemática através de operadores, operandos, parênteses 
e chamadas de função. Os operadores podem ser unários, binários ou 
até mesmo ternários (C, C++ e Java). No caso dos operadores 
binários, a maioria deles tem processamento infixo, ou seja, os 
operadores são colocados entre os operandos.
O resultado de uma expressão depende de precedência que 
a linguagem considera. Por exemplo:
a + b * c
A matemática diz que a multiplicação e a divisão precedem a 
soma e subtração, portanto se esta expressão fosse considerar esta 
regra, a multiplicação seria executada antesda soma.
5 + 3 * 2 = 11
Caso a avaliação seja feita da esquerda para direita, o 
resultado será 16.
Abaixo temos uma tabela de precedência de algumas 
linguagens imperativas:
Fortran Pascal C Ada
Mais alta ** *, /, div, mod ++, -- (pós) **, abs
*, / todos +, - ++, -- (pré) *, /, mod
todos +, - +, - (unário) +, - (unário)
*, /, % +, - (binário)
Mais baixa +, - (binário)
Quando temos uma seqüência de operadores com mesma 
Paradigmas de Linguagens de Programação - versão 2011 14
Prof. Kesede R Julio
precedência, o ordem de avaliação será imposta pela regra de 
associatividade. Na maioria das linguagens, esta regra diz que a 
avaliação será feita da esquerda para a direita. Em Fortran a 
exponenciação é associativa da direita para a esquerda.
5 ** 1 ** 2 =
= 5 ** 1 = 5
As regras de precedência e associatividade podem ser 
modificadas através de parênteses. Ex. Em Pascal:
(A + B) * C
Algumas linguagens também permitem o uso de operadores 
condicionais. Um exemplo disso é o operador ternário ?:, usado em C, 
C++ e Java. Por exemplo, em C podemos escrever:
if (cont==0){
media=0;
}
else{
media=soma/cont;
}
Ou:
media=(cont==0)?0:soma/cont;
A expressão (cont==0) antes do “?” é avaliada, caso seja 
verdadeira, toda a expressão valerá “0”; caso contrário será 
“soma/cont”.
Um estudo importante a ser feito também é o efeito 
colateral na ordem de avaliação. Por exemplo, podemos ter efeito 
colateral funcional, que acontece quando uma função modifica o valor 
Paradigmas de Linguagens de Programação - versão 2011 15
Prof. Kesede R Julio
de seu parâmetro. Considere:
...
a=10;
b=a+fun(a);
...
int fun(&a){
int b=a/2;
a=a*2;
return b;
}
Se a função não modificar o parâmetro não teremos 
problema, porem se houver modificação a ordem da avaliação dos 
operandos incidirá diretamente no resultado. Por exemplo, vamos 
considerar que a função “fun()” retorne o valor do parâmetro dividido 
por 2 (5) e modifique o valor do parâmetro para o seu dobro (20). A 
ordem de avaliação aqui é muito importante, pois se “a” for trazido da 
memória antes da execução de fun(), então a expressão valerá 15; se 
fun() for avaliada antes, a expressão valerá 25.
O mesmo acontece com modificações em variáveis globais. 
Por exemplo:
...
int a=5;
int func1(){
a=17;
return 3;
}
void func2(){
a=a+func1();
Paradigmas de Linguagens de Programação - versão 2011 16
Prof. Kesede R Julio
}
void main(){
func2();
}
A ordem de avaliação dos operandos, neste caso, também 
alterará o resultado de a na função func2(). O resultado poderá ser 8 
ou 20.
Pascal e Ada permitem que a avaliação seja feita em qualquer 
ordem, definida pelo implementador, e portanto, estas linguagens 
estão sujeitas a efeitos colaterais. Java evita estes efeitos definindo que 
a avaliação será feita da esquerda para direita.
 2.1.1 Operadores Sobrecarregados
Um dos problemas de sobrecarga de operador é referente a 
legibilidade. Outro problema é o erro causado pelo esquecimento de um 
dos operandos tornando a semântica da expressão completamente 
diferente. Exemplo do & da linguagem C:
c = a&b;
A disponibilização de operadores diferentes para operações 
diferentes facilita a leitura e a depuração do código. Um exemplo 
clássico é o operador “/”. Considere a divisão de dois operandos 
inteiros (“a” e “b”) retornando o resultado em uma variável real (“c”), 
em C e em Pascal.
Em C : c=a/b;
Em Pascal : c:=a/b;
No caso de C, o retorno é a parte inteira do resultado real 
truncado e no caso do Pascal o retorno é real, pois existe um operador 
especificamente para inteiros (“div”).
Paradigmas de Linguagens de Programação - versão 2011 17
Prof. Kesede R Julio
Além dos operadores sobrecarregados pré-definidos, existem 
linguagens (Ada, C++) que permitem que os programadores possam 
sobrecarregar ainda mais os operadores.
A sobrecarga deve sempre ser usada com critérios, pois nada 
impede que o usuário defina um “*” como operador de soma.
 2.1.2 Erros em expressões
Os erros mais comuns que encontramos em expressões são 
erros de “overflow” (resultado da expressão não consegue ser 
representado na célula de memória reservada para seu 
armazenamento) e divisão por zero. Estes erros podem ser chamados 
também de “exceções”, podendo assim ser tratados pelo programador.
 2.1.3 Expressões Relacionais
As expressões relacionais são constituídas de operadores 
relacionais (maior, menor, maior ou igual, menor ou igual, diferente, 
igual) e seus operandos. O valor resultante de uma expressão 
relacionais é, geralmente, booleana. Os operadores relacionais têm 
sempre menor precedência que os aritméticos, assim:
a+1>2*b
as operações aritméticas de cada lado do operador maior “>”, 
serão executadas primeiro.
 2.1.4 Expressões Booleanas
Expressões booleanas são formadas por operadores booleanos 
(not, and e or, nesta ordem de precedência na maioria das linguagens 
imperativas) e operandos que podem ser: expressões relacionais, 
variáveis e constantes. 
Aqui os operadores se misturam, e portanto precisamos de 
uma ordem de avaliação destas relações.
Paradigmas de Linguagens de Programação - versão 2011 18
Prof. Kesede R Julio
Mais alta
Mais baixa
**, abs, not
*, /, mod, rem
+, - (unários)
+, -, & (binários)
=, /=, <, >, <=, >=, in, not in
And, or, xor, and then, or else
Em C, como não existe o tipo booleano, o retorno da 
avaliação da expressão booleana é 0 (zero) quando falso e 1 (um) 
quando verdadeiro. Uma situação interessante em C é a validação da 
seguinte expressão:
a>b>c
como os operadores relacionais em C são associativos à 
esquerda, “a>b” é avaliado e o resultado é comparado com “c”.
Em linguagem com tipos booleanos, os operandos das 
expressões booleanas também devem ser booleanos. Em Pascal, os 
operadores booleanos tem precedência sobre os operadores relacionais, 
e portanto está incorreta a expressão:
a > 5 or a < 0
pois 5 não é um operando booleano. O correto seria:
(a > 5) or (a < 0)
 2.1.5 Avaliação Curto-Circuito
Usamos este termo quando o resultado de uma expressão é 
determinado sem avaliar todos os operandos e/ou operadores. 
Exemplo:
(a>=0) and (b<10)
se a for menor que zero, a expressão relacional “b<10” não é 
avaliada, pois “false and x = false”, independente do valor de x.
Suponha a seguinte expressão em C:
Paradigmas de Linguagens de Programação - versão 2011 19
Prof. Kesede R Julio
(a>b) || (b++ / 3)
neste caso, b só será modificado se “a>b= false”.
Em Ada a avaliação pode ser determinada pelo programador, 
então:
indice:=1;
while (indice <= limite) and then (lista(indice) /= chave)
loop
indice := indice + 1;
end loop;
Caso índice for maior que limite, não teremos a avaliação da 
expressão relacional “lista(índice)/=chave”, e assim evitamos o erro.
Em C, os operadores && e || são curto circuitos, porem & e | 
bit a bit, que podem ser usados em expressões booleanas, não são 
curto-circuitos.
 2.2 Comandos
Assim como as expressões respondem pela transformação dos 
dados, os comandos são responsáveis pela mudança de estado 
do conteúdo das variáveis. Podemosdividí-los em dois grandes 
grupos: aqueles que mudam o estado das variáveis, propriamente 
dito e aqueles que controlam o fluxo da execução do programa, 
ditando quais serão as próximas instruções a serem executadas.
 2.2.1 Instruções de Atribuição
Através delas podemos modificar dinamicamente as 
vinculações de valores a variáveis. Existem várias formas de utilizarmos 
atribuição, são elas:
Atribuição simples:- A forma mais simples de atribuição é:
Paradigmas de Linguagens de Programação - versão 2011 20
Prof. Kesede R Julio
<variável alvo> <op de atrib> <expressão>
Linguagens que usam “=” para atribuição pode causar 
confusão com a igualdade condicional. Por exemplo, em PL/I
A=B=C
o retorno da expressão condicional “B=C” é atribuído para 
“A”. O ideal é usar um símbolo diferentes para os diferentes propósitos 
(:= do Algol, primeira linguagem a usar este símbolo para atribuição).
Alvos Múltiplos:- Podemos definir vários alvos para o 
resultado de uma expressão. Em PL/I:
SOMA, TOTAL=0
Alvos Condicionais:- O alvo depende de uma condição. 
Exemplo em C++:
bandeira? Cont1=0 : cont2 = 0;
equivale a
if (bandeira) cont1=0; else cont2=0;
Operadores de Atribuição Compostos:- uma forma de 
abreviar a instrução de atribuição em algumas linguagens (Algol, C, C+
+, Java). Exemplo em C:
soma += valor;
equivale a
soma=soma+valor;
Operadores de Atribuição Unários:- As linguagens C, C++ 
e Java oferecem operadores aritméticos para incremento (++) e 
decremento (--) posfixados (a++) ou prefixados (++a). Exemplos em 
C:
• soma = ++cont; 
Paradigmas de Linguagens de Programação - versão 2011 21
Prof. Kesede R Julio
cont é incrementado em 1 e depois atribuído a soma.
• soma = cont++;
cont é atribuído para soma e depois incrementado em 1.
• cont++;
incrementa 1 na variável cont e atribui o resultado a cont.
Quando dois operadores unários são aplicados em um mesmo 
operando existe a associatividade da direita para a esquerda. Exemplo 
em C:
-cont++;
cont é incrementado em 1 e depois torna-se negativo.
Um problema comum em C é o operador de atribuição ser 
usado ao invés de um operador condicional. Exemplo:
if (x=y) ...
aqui, y é atribuído para x e o valor de x é avaliado, se for 0 
(zero) a expressão é falsa e se for diferente de 0 (zero) é avaliada 
como verdadeira. Java não permite que isto aconteça rejeitando 
expressões não booleanas nas instruções if.
 2.2.1 Instruções Compostas e Blocos
Instruções compostas são estruturas da linguagem capaz de 
tratar como um único comando, vários comandos. Este tipo de 
estruturas (seqüência de instruções) requerem que tenhamos 
delimitadores, afim de ser definido onde começa e onde termina a 
instrução composta. Delimitador em C, C++ e Java: “{” e “}”; em 
Pascal e Algol 60: “begin” e “end”.
Já os blocos de comandos permitem declarações de variáveis 
locais em sua estrutura, seguida de uma seqüência de comandos. 
Pascal, por exemplo, só permite bloco de comandos definidos em 
programas ou sub-rotinas (apenas nos blocos de comandos são 
Paradigmas de Linguagens de Programação - versão 2011 22
Prof. Kesede R Julio
permitidos declaração de variáveis), ou seja, não é permitida esta 
construção para qualquer outro propósito. 
 2.2.2 Condicionais
Comandos condicionais são aqueles que permitem que o 
programa execute determinada(s) instrução(ões) de acordo com uma 
condição, ou seja, podemos selecionar quais instruções devem ser 
executadas. Existem dois tipos de seleção que podemos fazer: seleção 
bidirecional e seleção n-direcional.
Comandos bidirecionais existem em todas as linguagens de 
programação. Exemplo em C:
if (a<5){
b=7;
}
else{
b=10;
} 
Nos comandos n-direcionais, uma seqüência de instruções 
podem ser seguidas, ao invés de apenas duas. Exemplo em Pascal:
case letra of
'a', 'e': begin
contae:=contae + 1
end;
'i', 'o': begin
contio:=contio + 1
end;
'u' : begin
contu:=contu + 1
end;
Paradigmas de Linguagens de Programação - versão 2011 23
Prof. Kesede R Julio
else begin
contcons := contcons + 1
end
 2.2.3 Iterativos
Os comandos iterativos são constituídos basicamente de corpo 
do comando e controlador da iteração. No corpo do comando estão as 
instruções a serem executadas, dependendo da condição contida no 
controlador da iteração. Existem os comandos iterativos com numero 
de iterações preestabelecido e os comandos iterativos com numero de 
iterações indefinido.
Aqueles que são preestabelecidos, o numero de iterações é 
determinado a priori através de uma variável de controle. O numero de 
iterações define quantas vezes as instruções contidas no corpo do 
comando serão executadas. Sintaxe do comando em Pascal:
for <variável> := <expressão 1> (to/downto) <expressão 2 
> do
<corpo do comando>
Aqui, a variável de controle é inicializada pela expressão 1 e é 
incrementada de 1 (to) ou decrementada de 1 (downto) até que seja 
maior ou menor, respectivamente, que a expressão 2. Enquanto isto 
não acontecer, o corpo do comando é executado. A variável de controle 
não pode ser modificada no interior do corpo do comando.
Algumas linguagens (C, C++ e Java) permitem a modificação 
da variável no corpo do comando, assim como mais de uma variável de 
controle. Exemplo em C:
somai=0;
somar=0.0;
for (i=10,r=2.0; (i<100 || r<20.0);i=i+2,r=r*2.5){
Paradigmas de Linguagens de Programação - versão 2011 24
Prof. Kesede R Julio
somai=somai + i;
 somar=somar + r;
}
Os comandos com numero de iterações indefinido são 
controlados por uma ou mais condição que pode ser avaliada no inicio 
ou no final do comando. Em C, Java, Ada, C++, temos o comando 
while que avalia a expressão condicional antes da execução das 
instruções que fazem parte do corpo do comando. A avaliação pode 
também ser feita no final do comando (do-while, repeat-until). Exemplo 
em C:
somai=0;
somar=0.0;
i=10;
r=2.0;
while ( i<100 || r<20.0){
 somai=somai + i;
 somar=somar + r;
 i=i+2;
 r=r*2.5;
}
Neste exemplo, como em qualquer caso dos comandos 
iterativos indefinidos, podemos alterar as variáveis que estão sendo 
avaliadas na expressão condicional.
 2.2.4 Desvio Incondicional
Este tipo de comando transfere a execução do programa para 
qualquer local desejado pelo programador. Esta flexibilidade, porem 
torna-se um problema, pois não existe observância alguma das 
estruturas já estabelecidas. O Fortran foi a primeira linguagem a utilizar 
este comando (goto), no entanto, caiu em desuso devido a indisciplina 
Paradigmas de Linguagens de Programação - versão 2011 25
Prof. Kesede R Julio
do comando e a ilegibilidade do código causado por ele. O desvio é feito 
para um rótulo que pode estar localizado tanto antes, como depois do 
comando. Exemplo em C:
...
a=0;
volta: a=a + 1;
if (a<10){
goto volta;
}
...
Quando a execução alcança o comando goto, ela volta a 
executar “a=a+1;”, no entanto, só alcançará o goto se “a<10”. Este 
comando é EXTREMAMENTE não recomendado.
 2.3 Abstrações
Ao falarmos de abstração pensamos no problema como um 
todo e não nos detalhes de sua resolução. No entanto, quem 
desenvolve a abstraçãodeverá pensar em como resolver, ao passo 
que quem irá utiliza-la deverá pensar apenas o que ela faz. Existem 
dois tipos de abstração disponíveis nas linguagens: de processo e de 
tipo.
 2.3.1 Abstração de Processos
Os processos funcionam como uma caixa-preta, ou seja, 
esconde os detalhes de implementação da resolução do problema. 
Podemos desenvolver dois tipos de abstração de processos: funções e 
procedimentos.
Paradigmas de Linguagens de Programação - versão 2011 26
Prof. Kesede R Julio
 2.3.1.1 Funções
Uma função é a representação do mapeamento entre o 
domínio e a imagem da função. Para cada conjunto de dados de 
entrada (domínio) teremos um dado como saída (imagem). 
Podemos encontrar este tipo de abstração em linguagens 
imperativas, funcionais e OO.
Exemplo de uma função em Pascal: Cálculo de 
exponenciação:
function pot (x:Real;n:Integer):Real;
begin
if n=1 then 
pot:=x;
else
pot:=x*pot(x,n-1)
end
Aqui temos o identificador da função “pot”, “x” e “n” são os 
parâmetros formais, o ultimo “Real” da primeira linha é o tipo do valor 
resultante e o que estiver entre “begin” e “end” é o bloco de comandos 
que descreve o comportamento da função, neste caso, o comando 
“if-else”. Para retornar o resultado, há uma atribuição para o nome da 
função: “pot:=x*pot(x,n-1)” . Neste caso, pot é uma pseudo-variável, 
pois a cada nova chamada recursiva uma nova variável é criada e 
colocada em uma pilha de solução da função. Para executar esta 
função, o usuário deverá escrever “pot(3.0,2)”, caso queria a base 3 
elevado a segunda potência. Em C, poderíamos colocar toda a 
expressão “x*pot(x,n-1)” no próprio retorno, assim teríamos uma 
expressão pura, pois os valores seria guardados diretamente na pilha 
gerada pela recursão.
Paradigmas de Linguagens de Programação - versão 2011 27
Prof. Kesede R Julio
 2.3.1.1 Procedimentos
Assim como as funções, estas abstrações descrevem um 
comportamento computacional. Porém, não resulta em uma imagem a 
partir do domínio, como nas funções, mas sim, alteram o estado do 
programa através dos argumentos fornecidos a ele. Em C, os 
procedimentos são tratados como funções que retornam “void” (nulo). 
Um exemplo de sintaxe de um procedimento em Pascal:
 procedure P(PF1,...,PFn); 
<bloco>
Onde P é o identificador da procedure, PFi são os parâmetros 
formais e “<bloco>” é o conjunto de comandos que ditarão o 
comportamento do procedimento e mudará o estado do programa 
através de efeito colateral.
 2.3.1.2 Parâmetros
Chamamos de parâmetros os dados que são enviados para as 
funções e procedimentos. A expressividade dos processos estão 
diretamente ligados aos seus parâmetros. Exemplo em C:
float pot_restrita(){
float potência;
if (n==1){
potência=x;
}
else{
n=n-1;
potência=x*pot_restrita();
}
return potência;
Paradigmas de Linguagens de Programação - versão 2011 28
Prof. Kesede R Julio
}
...
int n=2;
float x=10;
void main(){
float pot10_2;
...
pot10_2=pot_restrita();
...
}
Neste exemplo, o usuário deverá saber o tipo de variável 
declarada internamente na função, pois os valores trabalhados pela 
função não são passados por parâmetro e portanto estão “escondidos”.
Quando temos as variáveis definidas como parâmetros, 
podemos enviar apenas as informações sem a preocupação de 
conhecer como serão estes valores manipulados. O mesmo exemplo 
com parâmetros:
float pot(float x, int n){
float potência;
if (n==1){
potência=x;
}
else{
potência=x*pot(x,n-1);
}
return potência;
}
A chamada para esta função seria pot(10,2).
Paradigmas de Linguagens de Programação - versão 2011 29
Prof. Kesede R Julio
Aos parâmetros declarados na abstração chamamos de 
parâmetros formais e a expressão associada a cada parâmetro formal 
chamamos de parâmetro real ou atual, seus valores são chamados de 
argumentos. 
 2.4 Exemplo de Linguagem: Pascal
Uma das principais linguagens usada para o ensino da 
programação é o Pascal. Aqui vamos colocar alguns exemplos da 
linguagem para conhecermos a semântica de seus principais 
elementos.
Exemplo 1: Programa em que o usuário entra com sua idade e o ano atual e o 
programa lhe informa o seu ano de nascimento.
Program AnoNasc;
Var
intIdade:integer;
intAno:integer;
intDataNascimento : integer;
Begin
write( 'Digite sua Idade:' );
readln (intIdade) ;
write( 'Digite o Ano Atual:' );
readln (intAno) ;
intDataNascimento := ( intAno - intIdade);
writeln( 'Voce nasceu em: ', intDataNascimento );
End.
Exemplo 2: Programa que mostra a utilização de ponteiros. Problema. Alterar o valor 
armazenado em uma variável usando um ponteiro que aponta para o endereço dessa 
Paradigmas de Linguagens de Programação - versão 2011 30
Prof. Kesede R Julio
variável.
Program Ponteiros;
Var a: integer;
 p: ^integer;
 Begin
 a := 8 ; // Guarda o valor 8 em a
 p := nil; // O ponteiro não guarda nenhum endereço
 writeln( 'Valor armazenado em a: ' , a );
 
 // Guarda no ponteiro o endereço da variável a
 p := @a ;
 writeln( 'Valor apontado por p: ' , p^ );
 
 // O comando abaixo é equivalente a “a:= 2 * a ;” , pois p
 // guarda o endereço de a (p aponta para a)
 a:= 2 * p^ ;
 writeln( 'O valor de a agora: ' , a ); // Imprime 16
 writeln( 'Valor apontado por p: ' , p^ ); // Imprime 16
 readln ;
 End.
Exemplo 3: Este programa ilustra a alocacao dinamica com ponteiros.
Problema. Alocar memória para um ponteiro, guardar nele um valor, depois colocar 
este valor em uma variável.
Program AlocacaoDinamica;
Var p: ^integer;
 v : integer ;
Begin
 new( p ); // Aloca memória para armazenar um inteiro
 p^ := 10 ; // Guarda um inteiro na posição apontada por p
 writeln( 'Valor armazenado na posicao de memoria: ', p^ );
 v:= p^ ; //Guarda em v o inteiro apontado por p
 writeln( 'Valor armazenado em v: ', v );
 dispose( p ); // Libera a memoria amarrada a p
 readln ;
Paradigmas de Linguagens de Programação - versão 2011 31
Prof. Kesede R Julio
End.
Exemplo 4: Este programa ilustra a utilização de enumeracoes.
Program Enumeracao;
 var diasSemana : (domingo, segunda, terca, quarta, quinta, sexta, sabado) ;
 Begin
 writeln( 'Depois de segunda vem quinta? ' , succ(segunda) = quinta );
 writeln( 'Depois de segunda vem terca? ' , succ(segunda) = terca );
 writeln( 'Antes de quinta vem quarta? ' , pred(quinta) = quarta );
 writeln( 'Antes de quinta vem segunda? ' , pred(quinta) = segunda );
 End.
Exemplo 5: Este programa mostra mostra como construir listas lineares usando 
ponteiros.
Program ListasLineares;
// Tipo de dados que representa um nó da lista
type TNo = record
 dado : integer ; // Dado armazenado no nó
 prox : ^TNo ; // Ponteiro para próximo nó
 end ;
Var pinicio: ^TNo; // Guarda endereço do 1º nó da lista
 p1: ^TNo; // Auxiliar. Guarda endereço de um nó
 resposta : char ; // Auxiliar. Controla repetição.
 
Begin
 pinicio := nil ;
 
 // Repetição que monta a lista, adicionando novos nós
 repeat
 new( p1 );
Paradigmas de Linguagens de Programação- versão 2011 32
Prof. Kesede R Julio
 write( 'Entre com novo inteiro: ' );
 readln( p1^.dado ) ;
 p1^.prox := pinicio ;
 pinicio := p1 ;
 write( 'Novo dado(S/N)?' );
 readln( resposta );
 resposta := upcase( resposta );
 Until resposta = 'N' ;
 // Percorre a lista, imprimindo seus elementos
 p1 := pinicio ;
 while( p1 <> nil ) do
 Begin
 writeln( 'Achei: ' , p1^.dado );
 p1 := p1^.prox ;
 End;
 // Percorre a lista, liberando memória alocada para os nós
 while( pinicio <> nil ) do
 Begin
 p1 := pinicio ;
 pinicio := pinicio^.prox ;
 dispose( p1 );
 End;
 readln ;
End.
Paradigmas de Linguagens de Programação - versão 2011 33
Prof. Kesede R Julio
 3 Paradigma Orientado à Objeto
 3.1 Tipo Abstrato de Dados
Chamamos de TAD (Tipo Abstrato de Dados) o agrupamento 
de dados (atributos), juntamente com os módulos (métodos) que 
manipulam estes dados. 
Um TAD pode ser disponibilizado para programas aos quais 
eles não foram escritos, à priori. Desta forma, podemos construir 
bibliotecas, reunindo (encapsulando) códigos e dados semanticamente 
relacionados. Isto permite a reutilização de processos computacionais 
já realizados e exaustivamente testados.
Para criarmos bibliotecas, a linguagem deve prover a geração 
de unidades de compilação (encapsulamentos compiláveis 
separadamente) para que o cliente possa melhor usufruir da 
capacidade de reutilização de processos computacionais.
Por exemplo, suponhamos a construção de uma TAD Pilha, 
contendo as seguintes operações:
cria(pilha) :- cria um objeto pilha
destroi(pilha) :- desaloca o espaço gerado
vazia(pilha) :- retorna verdadeiro ou falso, caso a pilha 
esteja vazia ou não, respectivamente.
empilha(pilha, elemento) :- insere um elemento na pilha
desempilha(pilha) :- retira um elemento da pilha
topo(pilha) :- retorna o topo da pilha
Assim, um cliente que quisesse usar esta TAD, poderia ter o 
seguinte código:
...
cria(pilha1);
Paradigmas de Linguagens de Programação - versão 2011 34
Prof. Kesede R Julio
empilha(pilha1, cor1);
empilha(pilha1, cor2);
if (!vazia(pilha1))
 temp=topo(pilha1);
…
Qualquer mudança de implementação da pilha não afetará o 
código do cliente, uma vez que o acesso aos métodos é feito através de 
sua assinatura.
Exemplos:
 
SIMULA 67: Uma das primeiras implementações de TAD foi 
realizada pelo SIMULA 67, através de classes. Sintaxe:
class <nome da classe>
begin
<declaracões de variáveis da classe>
<definições de sub-programas da classe>
<seção de código da classe>
end <nome_da_classe>
A seção de código é executada apenas uma vez, permitindo a 
inicialização das varáveis da classe, por exemplo. Uma restrição desta 
linguagem é a não proteção das variáveis da classe.
Ada: Esta linguagem permite a ocultação de suas 
representações. O encapsulamento é realizado por um elemento 
chamado de pacote. Há dois tipos de pacote: pacote de especificação e 
pacote de corpo.
A interface do encapsulamento integra o pacote de 
especificação e implementação das interfaces integram o pacote de 
Paradigmas de Linguagens de Programação - versão 2011 35
Prof. Kesede R Julio
corpo. Estes pacotes podem ser compilados separadamente, desde que 
o pacote de interface seja compilado primeiro.
Podemos tornar um tipo visível, porém não a sua 
representação. Assim declaramos o tipo na parte visível do pacote:
type TIPO_VERTICE is private;
Depois repetimos sua declaração completa na parte oculta.
Package TIPO_LISTA_ENCADEADA is
type TIPO_VERTICE is private
…
private
type TIPO_VERTICE;
type PTR is access TIPO_VERTICE;
type TIPO_VERTICE is record
INFO : INTEGER;
ELEM : PTR;
end record;
end TIPO_LISTA_ENCADEADA;
C++: Os TAD´s em C++ são realizados através da definição 
de suas classes. Eles são uma extensão da struct em C. São herdadas 
da linguagem SIMULA 67 e suas descrições são tipo de dados.
As unidades de programa que instanciam uma classe tem 
acesso as entidades públicas desta classe, através de suas instâncias.
Os dados da classe são chamados de atributos (membro de 
dados) e as funções de métodos (funções-membro). Todas as 
instâncias da classe compartilham de suas funções-membro, porém 
Paradigmas de Linguagens de Programação - versão 2011 36
Prof. Kesede R Julio
cada instância têm acesso ao seu próprio conjunto de atributos.
Podemos definir uma classe apenas com os cabeçalhos das 
funções-membro, tendo seu corpo definido no cliente. Isto fará com 
que as compilações ocorram separadamente, aliviando o custo 
computacional do cliente.
Visibilidade :- As entidades de uma classe podem ser visíveis 
ou não. Para isto temos as cláusulas private, public e protected. 
Quando a entidade é declarada como private, ela é visível apenas pela 
própria classe, quando é protected, é visível pela classe e pela classe 
filha (herança) e quando é public, é visível por todos os clientes que 
instanciarem um objeto da classe.
Construtor :- Podemos definir um construtor, que é uma 
função implicitamente chamada quando da instanciação de um objeto 
da classe. Além disso, podemos ter mais de um construtor para uma 
mesma classe, obviamente sobrecarregados.
Destrutor :- Podemos definir um destrutor, que é uma função 
implicitamente chamada quando da desalocação do objeto instanciado 
para a classe.
Tanto construtores, quanto destrutores não têm tipo de 
retorno e não podem ser chamados explicitamente (os construtores 
podem em algumas situações especiais).
Exemplo Classe: Mostre o uso de classes em C++, através de uma classe pilha.
#include <iostream.h>
#include <conio.h>
class pilha{
private:
int *ptr_pilha;
int tam_max;
int top_ptr;
public:
Paradigmas de Linguagens de Programação - versão 2011 37
Prof. Kesede R Julio
pilha(){
ptr_pilha = new int [100];
tam_max = 99;
top_ptr = -1;
}
~pilha(){
delete [] ptr_pilha;
}
void empilha(int numero){
if (top_ptr == tam_max)
cerr << "a pilha esta cheia";
else
ptr_pilha[++top_ptr] = numero;
}
void desempilha(){
if (top_ptr == -1)
cerr << "a pilha esta vazia";
else
top_ptr--;
}
int topo(){
return ptr_pilha[top_ptr];
}
int vazia(){
return top_ptr == -1;
}
void exibe(){
 int i;
if (top_ptr == -1)
cerr << "a pilha esta vazia";
else{
 i=0;
 while (i <= top_ptr)
 cout << ptr_pilha[i++] << endl; 
 }
}
};
Paradigmas de Linguagens de Programação - versão 2011 38
Prof. Kesede R Julio
int main(){
int top_one;
pilha stk;
 
stk.empilha(42);
stk.empilha(17);
stk.empilha(10);
stk.empilha(30);
stk.empilha(15);
stk.exibe();
getch();
top_one = stk.topo();
stk.desempilha();
stk.exibe();
getch();
stk.desempilha();
stk.desempilha();
stk.exibe();
getch();
}
 3.2 Herança
A herança veio resolver dois principais problemas: reutilização 
de uma classe com necessidade de ser modificada para a nova 
aplicação e também para organizar os programas. 
Herdar uma classe significa estender atributos e/ou funções 
de umaclasse já existente. Por exemplo, podemos já ter criado uma 
classe ponto, contendo como atributo “x” e “y”. Quando formos 
construir a classe circunferência, podemos declarar apenas o atributo 
“raio”, herdando os atributos “x” e “y” do centro da circunferência a 
partir da classe ponto.
Chamamos de classe derivada (subclasse), a classe que 
herda entidades de outra. Já a classe de onde as entidades foram 
Paradigmas de Linguagens de Programação - versão 2011 39
Prof. Kesede R Julio
herdadas, chamamos de classe-pai (superclasse). As chamadas aos 
métodos de uma classe chamamos de mensagens. Cada mensagem 
deve conter: o nome do objeto a qual pertence o método e o nome do 
método que deseja executar. Assim, um programa orientado à objetos 
é uma coleção de mensagens enviadas de um objeto à outro.
Podemos também modificar os métodos das classes herdadas. 
Chamamos isto de override (sobreposto). O novo método 
normalmente tem a mesma assinatura do método modificado. Usamos 
este tipo de recurso quando queremos especificar uma operação, 
mantendo a operação genérica na classe pai e especificando-a nas 
classes-filha.
Dois tipos de herança são possíveis: simples e múltipla. A 
herança simples ocorre quando temos apenas uma classe-pai. Já a 
herança múltipla ocorre quando a classe herda de mais de uma 
classe-pai. Podemos representar herança simples através de uma 
árvore de derivação e a herança múltipla através de um grafo de 
derivação.
Uma grande desvantagem da herança é a dependência gerada 
entre as classes, algo que não acontece com Tipos Abstratos de Dados.
A forma geral de herança de classe em C++ é:
class classe_derivada : modo_de_acesso nome_da_classe
{declarações do membro de dados e função membro};
Os modos de proteção (private, protected e public) são 
Paradigmas de Linguagens de Programação - versão 2011 40
B
DE
A M
F
Herança MúltiplaHerança simples
Prof. Kesede R Julio
redesenhados na derivação. Exemplo:
class classe_base{
private:
int a;
float x;
protected:
int b;
float y;
public:
int c;
float z;
};
class sub_classe_1 : public classe_base{ …};
class sub_classe_2 : private classe_base{ …};
Em sub_classe_1, “b”, “y” são protegidos , e “c”, e ”z” são 
públicos. Nenhuma classe derivada de sub_classe_2 tem acesso a 
qualquer membro de classe_base. Já os membros private de 
classe_base “a” e “x”, não são acessíveis a qualquer membro de 
sub_classes_1 e sub_classes_2.
Para que um membro de uma classe herdada como privada, 
possa ser acessado pela derivação de sua classe-filha, devemos 
reexportá-lo. Assim,
class sub_classe_3 : private classe_base{
classe_base :: c;
}
Agora, os objetos instanciados da sub_classe_3 podem 
acessar o membro “c” da classe_base. Os dois pontos duplos (::) são 
chamados de “operador de resolução de escopo” e especifica a qual 
classe pertence a entidade definida.
 3.3 Acoplamento dinâmico
É a ação do objeto, ao receber uma mensagem, de verificar 
Paradigmas de Linguagens de Programação - versão 2011 41
Prof. Kesede R Julio
em sua classe se há um método que defina como ele deve se 
comportar de acordo com a mensagem recebida. Se nada for 
encontrado em sua classe ele irá verificar na superclasse da sua classe, 
de onde ele possa ter herdado algo.
 3.4 Polimorfismo
É, de certa forma, decorrente do acoplamento dinâmico, pois 
é a característica em que, mesmo recebendo mensagens iguais, objetos 
receptores de mensagem diferentes podem gerar respostas diferentes, 
dependendo do método de sua classe. Mais importante, o objeto 
emissor não precisa conhecer a classe do objeto receptor e como este 
objeto irá responder à mensagem. Isto significa que, por exemplo, a 
mensagem print pode ser enviada para um objeto sem a necessidade 
de saber se o objeto é um caracter, um inteiro ou uma string. O objeto 
receptor responde com o método que é apropriado à classe a qual ele 
pertence.
 3.5 Exemplo de linguagem: Python
Muitas linguagens de programação foram criadas desde o 
início da computação, hoje em dia várias destas linguagens estão 
“extintas” e podemos considerar que linguagens como C++, Java e 
.NET são predominantes no mercado. O nome da linguagem é uma 
homenagem ao grupo humorístico inglês Monty Python.
Python vem sendo usada em projetos sérios por entidades 
como Yahoo, NASA, InfoSeek, MCI Worldcom, IBM e Hiway, a maior 
empresa de hospedagem de web-sites do mundo. É também a base do 
Zope, a mais sofisticada plataforma para construção de 
webapplications disponível hoje como open-source.
Paradigmas de Linguagens de Programação - versão 2011 42
Prof. Kesede R Julio
 3.5.1 Características
a. Programação orientada a objetos (incluindo herança 
múltipla, conceito apenas parcialmente presente em Java) ;
b. Exceções, um moderno mecanismo para o tratamento 
de erros;
c. Módulos, uma forma inteligente de acessar e 
organizar código a ser reutilizado ;
d. Coleta de lixo automática, sistema que elimina os 
erros causados pelo acúmulo de dados inúteis na memória 
do computador (característica presente também em Java, 
mas não em C++);
e. Recursos avançados de manipulação de textos, listas 
e outras estruturas de dados;
f. Portabilidade possibilidade de executar o mesmo 
programa sem modificações em várias plataformas de 
hardware e sistemas operacionais (uma virtude de Java, 
mas difícil de se conseguir em C++)
Portanto podemos perceber que o Python é uma linguagem 
simples e robusta nos oferecendo a maior parte das características 
importantes de linguagens modernas e amplamente utilizadas como 
Java, C++, Perl e VBScript.
 3.5.2 Elementos da linguagem
Tipos de variáveis:- Python é dinamicamente tipado, o que 
significa que se você usou uma variável para armazenar um inteiro, 
nada lhe impede de usá-la posteriormente para armazenar uma string 
(frase). Na verdade, variáveis em Python não são declaradas, o que lhe 
dá muita flexibilidade. Quem determina o tipo de uma variável é o 
próprio interpretador, você dificilmente precisa se preocupar com o tipo 
Paradigmas de Linguagens de Programação - versão 2011 43
Prof. Kesede R Julio
da variável, segue o exemplo abaixo:
• x = 2 # Inteiro
• p = 3.1415 # Real, ou ponto flutuante
• verdadeiro = True # Boolean
• estringue = 'alguma frase' # String
• c = 3 + 2j # Complexo
• lista = [3, 4, 5] # Lista com elementos inteiros
• lista2 = [2,'tres',4.0,[5,6]] # Lista mista e aninhada
• tupla = (1,2,3,'quatro') 
Tupla. É como uma lista, mas não pode ser mudada. tuplas de 0 
ou 1 elementos têm sintaxes especiais: 
tupla0 = ( )
tupla1 = ('primeiro e único item',) 
Repare na vírgula. Em alguns casos (atribuições, returns), os 
parênteses são opcionais, mas na maioria das vezes (tuplas dentro de 
listas, tuplas dentro de chamadas de funções) os parênteses são 
necessários porque a vírgula faz parte de outra sintaxe.
• coord = (4.5, 9.1)
• cor_branca = 255, 255, 255 # cor no formato RGB
• função ((4.5, 9.1), 'string')
• dic = {'site':'Python Brasil','url':'www.pythonbrasil.com.br'} 
#Isso é um dicionário
Abaixo listamos alguns os tipos primitivos implementados 
na linguagem:
• str (Strings, como 'blabla')
• unicode (São strs em que os caracteres podem representar 
qualquer língua,u'blabla')
• bool (True ou False)
• float (Números em ponto flutuante, como 4.5 ou 3.14e-10)
• int (Números inteiros, como 99)
• long (Números inteiros muito grandes, como 
1234567890123456789123456789L)
• complex (Números complexos, como 3.1j ou 7+3.14e-10j)
• file (Arquivos)
• decimal (integrado ao Python 2.4 como módulo) (Números 
fracionários representados de
forma decimal em vez de binária)
Paradigmas de Linguagens de Programação - versão 2011 44
Prof. Kesede R Julio
Os tipos compostos implementados na linguagem, são: list, 
tuple, dict, set.
Estruturas de Controle:- Algo interessante (e útil) em 
Python é a forma de estruturação do script da linguagem. Não existe 
nenhum caractere para delimitar blocos de códigos, como em outras 
linguagens ({} em C/C++, begin/end em Pascal etc). A delimitação dos 
blocos é dada pela endentação, ou seja, o programador é obrigado a 
organizar o programa, pois programas desorganizados não rodarão 
corretamente. Temos 3 estruturas de controle em Python, uma de 
decisão (if-elif-else) e duas iterativas (for e while). 
if-elif-else: O if o elif e o else servem para examinar 
expressões. Em português eles avaliam se determinada expressão 
retorna Verdadeiro ou Falso. Em Python os valores vazios: None, [] (* 
Lista vazia), "", 0. São tidos como Falso. E os outros valores são 
verdadeiros. Sintaxe:
 if condição:
 # bloco de código
 elif condição:
 # outro bloco
 else:
 # bloco final
Exemplo:
 a = 2
 b = 12
 if a < 5 and b * a > 0:
 print "ok"
Paradigmas de Linguagens de Programação - versão 2011 45
Prof. Kesede R Julio
Outro exemplo:
 if nome == "pedro":
 idade = 21
 elif nome == "josé": 
 idade = 83
 else:
 idade = 0
for: Algo bastante diferente e útil em Python é a sua iteração 
sobre listas. Veremos isto nos exemplos. A sintaxe geral do for é:
 for variável in seqüência:
 # bloco de código
 else:
 # bloco executado na ausência de um break
Exemplo 1: imprime números de 0 a 49
For i in range(50):
Print i
Exemplo 2: Mostra os nomes das estações contidos na lista
 >>> estacoes = ["verao", "outono", "inverno",”primavera”]
 >>> for e in estacoes:
 ... print e
 ...
 verao
 outono
 inverno
primavera
Exemplo 3: a variável i, varia de 1 a 4 (exclusive)
Paradigmas de Linguagens de Programação - versão 2011 46
Prof. Kesede R Julio
 >>> for i in range(1,4):
 ... print "%da volta" % i
 ...
 1a volta
 2a volta
 3a volta
while: existe a iteração enquanto uma condição não é 
satisfeita. A forma geral do while é:
while condição:
 # bloco de código
else:
 # bloco executado na ausência de um break
Exemplo 1:
opc = 1
while opc != 0:
# qualquer código
opc = int(raw_input("Digite 0 para sair \n > "))
Exemplo 2:
 >>> m = 3 * 19
 >>> n = 5 * 13
 >>> contador = 0
 >>> while m < n:
 ... m = n / 0.5
 ... n = m / 0.5
 ... contador = contador + 1
 ...
 >>> print "Iteramos %d vezes." % contador
Paradigmas de Linguagens de Programação - versão 2011 47
Prof. Kesede R Julio
 Iteramos 510 vezes.
Módulos:- Para criar um módulo em Python criamos um 
arquivo com nome <arq>.py no diretório de seu programa principal. 
Neste arquivo faça os defs e classes. No programa que chama o módulo 
importe este modulo usando import <arq>. Desta forma podemos 
reaproveitar o código com maior facilidade sem a necessidade de copiar 
e colocar um determinado código para seu sistema.
Classes:- Definimos uma classe através da palavra “class”. O 
método __init__() é o construtor da classe. Para referenciar atributos e 
métodos dentro de uma classe, usamos o prefixo self. Exemplo:
class Carro:
def __init__(self, preco):
self.marca = "Ford"
self.modelo = "Maverick"
self.ano = 74
self.cor = [0,200,50]
self.pos = [0,0]
def andar(self, x, y):
self.pos[0] = self.pos[0]+x
self.pos[1] = self.pos[1]+y
carango = Carro(5000) #passa o valor 5000 para __init__()
for i in range(300):
#executa o for 300 vezes simulando que o carro andou 
300 unidades de medida.
carango.andar(1,0) 
Herança:- Permite que se utilize código de outras classes. O 
Python permite herança simples e múltipla (pouco recomendada pela 
complexidade do código). Exemplo:
# classe pai
class CD:
Paradigmas de Linguagens de Programação - versão 2011 48
Prof. Kesede R Julio
def __init__(self, titulo):
self.titulo = titulo
def mudarTitulo(self, novoTitulo):
self.titulo = novoTitulo
# sub-classe
class CDAudio(CD):
def __init__(self, titulo, autor):
CD.__init__(self, titulo)
self.autor = autor
self.faixas = []
def adicionarFaixa(self, numero, nome):
self.faixas.append((numero, nome))
def removerFaixa(self, numero, titulo):
self.faixas.remove((numero, nome))
novoCD = CDAudio('Physical Graphitte', 'Led Zeppelin')
novoCD.adicionarFaixa(1,'Custard Pie')
novoCD.adicionarFaixa(2,'The Rover')
print dir(novoCD) #mostra os atributos do objeto novoCD
print "CD: %s, %s" % (novoCD.titulo, novoCD.autor)
print novoCD.faixas
List :- Permite processar listas de uma forma bem próxima a 
matemática. A sintaxe é:
[<expressão> for <variável> in <lista> if <condição>] 
Exemplo:
#mostra os múltiplos de 4 no range de zero a cem
[x for x in range(100) if x % 4 == 0]
[0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 
80, 84, 88, 92, 96]
Paradigmas de Linguagens de Programação - versão 2011 49
Prof. Kesede R Julio
 4 Paradigma Lógico
A forma de programação das linguagens lógicas nada tem a 
ver com as funcionais ou imperativas. Usamos aqui proposições 
juntamente com a lógica simbólica afim de inferirmos novas 
proposições. Damos a isto o nome de Cálculo de Predicados, que é a 
base da programação lógica. 
 4.1 Proposições
Proposição é uma declaração lógica da relação entre objetos, 
que pode ou não ser verdadeira. Os objetos podem ser termos simples, 
constantes ou variáveis. 
As proposições mais simples (proposições atômicas) são 
formadas por termo composto. O termo composto consiste em um 
functor, que nomeia a relação, e uma lista de parâmetros. Exemplo:
homem(jake)
gosta(bob, bife)
Neste caso, homem e gosta são functores e jake, bob, bife 
são parâmetros. A primeira relação, com um único parâmetro 
chamamos de 1-tupla e a segunda, com 2 parâmetros chamamos de 
2-tupla. Esta nomenclatura segue de acordo com a quantidade de 
parâmetros. Todos os termos simples desta relação são constantes. O 
Paradigmas de Linguagens de Programação - versão 2011 50
Prof. Kesede R Julio
que dará significado as relações não serão seus nomes, mas sim o 
contexto do problema a ser resolvido.
Podemos ligar duas proposições através de conectores 
lógicos, formando assim, proposições compostas. A tabela abaixo 
mostra os conectores e seus significados.
Nome Símbolo Exemplo Significado Precedência
Negação ¬ ¬a não a Mais alta
Conjunção ∩ a b∩ a e b
Disjunção ∪ a b∪ a ou b
Equivalência ≡ a b≡ a é equivalente a b
Implicação 
⊃ a b⊃ a implica b
⊂ a b⊂ b implica a
Mais baixa
Exemplo de proposições compostas:
a ¬ b c∩ ⊃
Obedecendo a precedência, a avaliação desta proposição seriarealizada como:
(a (∩ ¬ b)) ⊃ c
Podemos acrescentar variáveis a nossas proposições, desde 
que acompanhadas de quantificadores existenciais (existe ( )) e∃ 
universais (qualquer (V)) e separadores (.). Exemplos:
1. VX.(mulher(X) humano(X))⊃
2. ∃X.(mãe(mary,X) homem(X))∩
O exemplo 1 diz que qualquer valor de X, sendo X mulher, X é 
humano. Toda mulher é humano.
O exemplo 2 diz que existe um X, cujo Mary é mãe e X é 
homem. Mary tem um filho.
Os quantificadores tem precedência sobre todos os 
Paradigmas de Linguagens de Programação - versão 2011 51
Prof. Kesede R Julio
operadores e seu escopo limita-se as proposições atômicas, a menos 
que as proposições sejam estendidas por parênteses, como nos 
exemplos acima.
 4.2 Forma Clausal
A forma clausal é a maneira mais simples de se expressar 
proposições e evitar redundâncias. A forma sintática geral é:
B1 B∪ 2 ... ∪ B∪ n ⊂ A1 A∩ 2 ... A∩ ∩ m 
Aqui, se todos os A's forem verdadeiros, pelo menos um B 
será verdadeiro. As conjunções (and) devem ser colocadas do lado 
direito, e as disjunções (ou), do lado esquerdo. Esta forma dispensa os 
quantificadores existenciais ( ) ∃ e os universais (V) ficam implícitos no 
uso de variáveis nas proposições atômicas.
Qualquer cálculo de predicado pode ser convertido para forma 
clausal. O lado direito de uma proposição chamamos de “antecedente” 
e o lado esquerdo de “conseqüente”. Exemplos de proposições na 
forma clausal:
1. gosta(bob, truta) ⊂ gosta(bob, peixe) ∩ peixe(truta)
2. pai(louis, al) ∪ pai(louis, violet) ⊂ pai(al, bob) ∩ mãe(violet, 
bob) ∩ avô(louis, bob)
No primeiro exemplo, se bob gosta de peixe e peixe é truta, 
logo bob gosta de truta.
No segundo exemplo, se al é pai de bob e violet é mãe de bob 
e louis é avô de bob, logo louis é pai de violet ou louis é pai de al.
Este método também foi explorado para Demonstração de 
Paradigmas de Linguagens de Programação - versão 2011 52
Prof. Kesede R Julio
Teoremas. 
 4.3 Cálculo de Predicados e Demonstração de Teoremas
O cálculo de predicados permite a inferência de novas 
proposições a partir de proposições dadas. A esta regra de inferência, 
damos o nome de Resolução. A resolução foi idealizada para ser 
aplicada à forma clausal e se comporta da seguinte maneira: 
Dadas as proposições
P1 ⊂ P2
Q1 ⊂ Q2
Neste caso, P2 implica P1 e Q2 implica Q1 . 
Considerando que P1 seja idêntico a Q2 , podemos substituir P1 e 
Q2 por T. Assim:
T ⊂ P2
Q1 ⊂ T
Podemos inferir que P2 implica Q1 , pois P2 implica T e 
T implica Q1 .
Consideremos outras duas proposições:
mais velho (joanne, jake) ⊂ mãe(joanne, jake)
mais sábio(joanne, jake) ⊂ mais velho(joanne, jake)
Utilizando a mesma lógica de construção de resolução do 
exemplo anterior, teríamos a nova proposição da seguinte forma:
mais sábio(joanne, jake) ⊂ mãe(joanne, jake)
Esta mecânica de construção é simples. Agrupamos os termos 
do lado esquerdo das proposições utilizando um E, e fazemos a mesma 
coisa do lado direito. Após o agrupamento, cancelamos os termos 
Paradigmas de Linguagens de Programação - versão 2011 53
Prof. Kesede R Julio
iguais dos dois lados. Pronto, temos agora a nova proposição. Observe 
o exemplo:
pai(bob, jake) ∪ mãe(bob, jake) ⊂ pais(bob, jake) 
avô(bob, fred) ⊂ pai(bob, jake) ∩ pai(jake, fred) 
aplicando a resolução:
mãe(bob, jake) ∪ avô(bob, fred) ⊂ pais(bob, jake) ∩ pai(jake, 
fred)
A resolução complica quando inserimos variáveis nas 
proposições, pois a resolução exige que seus valores sejam 
encontrados, a fim de que a comparação seja bem sucedida. O valor 
encontrado nem sempre é satisfatório e um outro valor deverá ser 
atribuído para nova avaliação. Ao processo de determinação de valores, 
damos o nome de unificação e a atribuição temporária de valores às 
variáveis que permite a unificação, damos o nome de instanciação.
Um uso fundamental da resolução é na demonstração de 
teorema. Assim, construímos as nossas hipóteses através de 
proposições pertinentes. Uma outra proposição é construída a fim de 
negar as proposições anteriores, chamamos isto de meta. Este tipo de 
demonstração é a prova pela contradição. O objetivo aqui é encontrar 
uma contradição entre as proposições dadas.
Proposições usadas na resolução, obedecem uma forma 
clausal restrita e pode ser escrita apenas de duas formas: cláusulas 
com cabeça (relações) e sem cabeça (fatos) (Cláusulas de Horn). 
Exemplo de relação:
gosta(bob, truta) ⊂ gosta(bob, peixe) ∩ peixe(truta)
exemplo de fato:
pai(bob, jake)
Paradigmas de Linguagens de Programação - versão 2011 54
Prof. Kesede R Julio
Nas Cláusulas de Horn existem apenas uma proposição 
atômica do lado esquerdo, ou nenhuma. A grande maioria das 
proposições podem ser declaradas desta forma.
 4.4 Elementos básicos do Prolog
Termos:- Um termo pode ser uma constante, uma variável 
ou uma estrutura.
Uma constante é um átomo ou um número inteiro. O átomo 
pode ser um conjunto de letras, dígitos etc , e se inicia com letra 
minúscula. Ex.: jake
Uma variável é um conjunto de letras, dítos etc, e se inicia 
com letra maiúscula. Ex.: X
Uma estrutura é uma proposição, que pode ser um fato, uma 
relação ou uma consulta. Ex.: homem(Vinicius)
Fatos :- (Cláusula de Horn, sem-cabeça) São proposições 
dadas como verdadeiras e utilizadas para para consulta, a fim de inferir 
um novo fato ou relação. São sempre incondicionais. Ex.:
mulher (shelley). (shelley é mulher)
homem(bill). (bill é homem)
pai(bill, jake). (bill é pai de jake)
No último exemplo, apenas pré-supomos a semântica, pois 
não temos um contexto.
Regras :- (Cláusula de Horn, com-cabeça) são proposições 
condicionais contendo um antecedente (lado direito) e um conseqüente 
(lado esquerdo). Se (if) o lado direito for verdadeiro, o lado esquerdo 
também será (then). O antecedente pode conter várias proposições 
Paradigmas de Linguagens de Programação - versão 2011 55
Prof. Kesede R Julio
amarradas por conjunções, porém o lado conseqüente será atômico. 
Uma conjunção em Prolog é denotado por “,” (vírgula). Ex.:
mulher(shelley), filho(shelley).
A forma geral de uma regra é:
conseqüente :- antecedente.
Os caracteres “:-” simbolizam o implica (⊂) da programação 
lógica. Assim, conseqüente só será resolvido se antecedente for 
verdadeiro, ou tornar-se verdadeiro através da instanciação de suas 
variáveis. Ex.:
antepassado(mary, shelley) :- mãe(mary, shelley).
Neste caso, se mary for mãe de shelley, mary é antepassado 
de shelley.
Podemos também usar variáveis para que o significado das 
proposições sejam generalizadas. Exs.:
pais(X, Y) :- mãe(X, Y).
pais(X, Y) :- pai(X, Y).
avô(X, Z) :- pai(X, Y), pai(Y, Z).
irmãos(X, Y) :- mãe(M, X), mãe(M, Y), pai(F, X), pai(F, Y).
O significado do conjunto de cláusulas acima é:
se X é mãe de Y, então X é um dos pais de Y.
se X é pai de Y, então X é um dos pais de Y.
se X é pai de Y e Y é pai de Z, então X é avô de Z.
Se M é mãe de X e M é mãe de Y e F é pai de X e F é pai de Y, 
então X e Y são irmãos.
Metas :- (Cláusula de Horn, sem-cabeça) As metas ou 
consultas são proposições para verificação de aprovação ou 
desaprovação de um teorema, a partir de uma base de conhecimento 
Paradigmas de Linguagens de Programação - versão 201156
Prof. Kesede R Julio
constituído por fatos e regras. Ex.:
homem(fred).
Neste caso, o sistema responderá “yes” ou “no”. “Yes”, 
significa que a meta é verdadeira considerando a base de 
conhecimento. “No”, significa que que a meta é falsa ou que o sistema 
é incapaz de prová-la.
Podemos fazer consultas usando variáveis, assim o sistema 
instancia a variável para provar a veracidade da proposição. Ex.:
pai(X, mike).
Através da unificação o sistema tentará um valor para X que 
resulte na veracidade da proposição, caso não encontre retornará “no”.
Processo de Inferência :- Para que o Prolog conclua uma 
meta, é necessário encontrar na base de conhecimento um fato ou 
então um encadeamento de fatos e regras que possam torná-la 
verdadeira. Quando temos uma proposição composta como meta, cada 
um dos fatos torna-se uma submeta. Assim, para satisfazer a meta Q, 
poderíamos ter:
P2 :- P1
P3 :- P2
…
 Q :- Pn
Considere agora a consulta abaixo:
homem(bob).
Caso a base de conhecimento contenha o fato homem(bob), 
temos a conclusão da meta satisfeita de forma direta, porém considere 
a base de conhecimento abaixo.
pai(bob).
Paradigmas de Linguagens de Programação - versão 2011 57
Prof. Kesede R Julio
homem(X) :- pai(X).
A conclusão não é trivial uma vez que não temos um fato para 
casarmos diretamente com a meta. Assim, o sistema procurará o 
primeiro termo contendo o functor da meta e fará a instanciação da 
variável X para bob. Portanto homem(X) tornará homem(bob), e com 
esta instanciação feita, pai(X) torna-se pai(bob). pai(bob) torna-se 
verdadeira, a partir do primeiro fato da base. A este tipo de inferência 
usada pelo Prolog chamamos de “encadeamento retrógrado”.
Um outro recurso usado pelo Prolog para inferir metas, é 
chamado de backtracking. Ele é usado quando uma meta de proposição 
composta (ou seja, com submetas) tenta ser inferida. O sistema tenta 
provar uma submeta, e na falha desta tentativa, retorna tentando 
provar a submeta anterior. Isto pode se tornar bem complexo e 
demorado, dependendo da organização da base de conhecimento e da 
meta. Considere o exemplo de meta abaixo: Existe um homem X, tal 
que X seja um dos pais de shelley?
homem(X), pais(X, shelley).
Neste caso, o sistema procurará um fato com o functor igual 
ao da primeira meta. Encontrando, ele verificará se esta instancia de X 
é um dos pais de shelley. Caso não seja, o sistema retorna 
(backtracking) para o próximo functor homem para uma nova 
instanciação e tentará novamente provar que esta nova instanciação é 
um dos pais de shelley. Seria muito mais rápida a busca se as 
proposições da meta estivessem invertidas (pais(X, shelley), 
homem(X)). Assim, o sistema primeiro procuraria um X que fosse um 
dos pais de shelley e depois verificaria se X é homem, ao invés de 
procurar um homem e depois verificar se o mesmo é um dos pais de 
Paradigmas de Linguagens de Programação - versão 2011 58
Prof. Kesede R Julio
shelley. Afirmamos isto porque, supostamente existiriam na base bem 
mais homens, do que pais de shelley.
Passamos agora a descrever este processo de resolução do 
Prolog através de um exemplo de computação numérica.
O operador “is” do Prolog permite a instanciação de uma 
variável por uma expressão. Exemplo:
A is B / 17 + C.
Se A não estiver instanciada, mas B e C estiverem, A receberá 
o valor da expressão. Assim, a cláusula é satisfeita. Porém, se A estiver 
instanciado e B ou C não estiverem, a cláusula não será satisfeita. 
Cuidado o “is” não funciona como um comando de atribuição das 
linguagens imperativas.
Consideremos agora uma base de conhecimento contendo a 
velocidade média de vários carros, assim como o tempo que cada um 
deles permaneceram na pista. Estes serão nossos fatos. A distância que 
cada um percorreu pode ser dada como uma relação. Assim, teremos a 
seguinte base de conhecimento:
velocidade(ford, 100).
velocidade(chevy, 105).
velocidade(dodge, 100).
velocidade(volvo, 100).
tempo(ford, 20).
tempo(chevy, 21).
tempo(dodge, 24).
tempo(volvo, 24).
distância(X, Y) :- velocidade(X, Velocidade), tempo(X, 
Tempo), Y is Velocidade * tempo.
Consideremos agora uma consulta que deseja descobrir qual a 
Paradigmas de Linguagens de Programação - versão 2011 59
Prof. Kesede R Julio
distância percorrida pelo chevy:
distância(chevy, Distância_do_Chevy).
Para entendermos a execução desta consulta, vamos recorrer 
à uma estrutura do Prolog chamada “trace”. Esta estrutura permite o 
rastreamento da execução passo-a-passo. Vamos entender primeiro os 
4 eventos possíveis do “trace”. (1) Call :- tentativa de satisfazer uma 
meta. (2) Exit:- meta satisfeita. (3) Redo :- tentativa de satisfazer 
novamente a meta. (4) fail :- meta não satisfeita. Call e Exit podem ser 
entendidos como uma chamada e retorno de função, respectivamente.
Voltemos ao exemplo usando o trace.
trace.
distância(chevy, Distância_do_Chevy).
(1) 1 Call: distância(chevy, _0)?
(2) 2 Call: velocidade(chevy, _5)?
(2) 2 Exit: velocidade(chevy, 105)
(3) 2 Call: tempo(chevy, _6)?
(3) 2 Exit: tempo(chevy, 21)
(4) 2 Call: _0 is 105*21?
(4) 2 Exit: 2205 is 105*21
(1) 1 Exit: distância(chevy, 2205)
Distância_do_Chevy = 2205
O caractere “_” (underline) é usado para identificar variáveis 
a serem instanciadas pelo sistema. Existem 4 colunas mostradas pelo 
trace. A 1ª mostra um número que corresponde a submeta a ser 
Paradigmas de Linguagens de Programação - versão 2011 60
Prof. Kesede R Julio
satisfeita. A 2ª mostra a profundidade da chamada. A 3ª mostra o tipo 
de evento. A 4ª mostra a própria linha de instrução Prolog.
Neste exemplo, nenhum evento “redo” é executado, pois o 
backtracking é desnecessário. Vejamos agora um exemplo usando 
backtracking.
Consideremos a base de conhecimento abaixo:
gosta(jake, chocolate).
gosta(jake, damascos).
gosta(darcie, alcaçuz).
gosta(darcie, damascos).
Agora consideremos a consulta rastreada.
trace.
gosta(jake, X), gosta(darcie, X).
(1) 1 Call: gosta(jake, _0)?
(1) 1 Exit: gosta(jake, chocolate)
(2) 1 Call: gosta(darcie, chocolate)?
(2) 1 Fail: gosta(darcie, chocolate)
(2) 1 Redo: gosta(jake, _0)?
(1) 1 Exit: gosta(jake, damascos)
(3) 1 Call: gosta(darcie, damascos)?
(3) 1 Exit: gosta(darcie, damascos) 
X = damascos
Agora veremos uma segunda estrutura básica do Prolog: a 
estrutura de Lista. Exemplo:
Paradigmas de Linguagens de Programação - versão 2011 61
Prof. Kesede R Julio
[maça, ameixa seca, uvas, kumquat]
Uma lista sempre apareça entre colchetes e [] denotará uma 
lista vazia.
Não há uma função especifica para construir ou dividir uma 
lista. Para isto usamos a seguinte notação: [X | Y], onde o elemento 
antes do “|” (pipe) é chamado de cabeça da lista e o segundo de cauda. 
Abaixo mostramos proposições usando lista.
nova_lista([maça, ameixa seca, uvas, kumquat]).
nova_lista([damasco, pêssego, pera]).
Poderíamos agora formular uma consulta capaz de dividir a 
lista. Assim:
nova_lista([Cabeça_da_Nova_Lista| Cauda_da_Nova_Lista])
Neste caso, Cabeça_da_Nova_Lista seria instanciado com o 
elemento maça e Cauda_da_Nova_Lista seria instanciado com [ameixa 
seca, uvas, kumquat].
Podemos também criar listas usando a mesma notação.
[Elemento_1 | Lista_2]
Se elemento_1 for instanciado

Outros materiais