Docsity
Docsity

Prepare-se para as provas
Prepare-se para as provas

Estude fácil! Tem muito documento disponível na Docsity


Ganhe pontos para baixar
Ganhe pontos para baixar

Ganhe pontos ajudando outros esrudantes ou compre um plano Premium


Guias e Dicas
Guias e Dicas


Introdução à programação, Notas de estudo de Cultura

INTRODUÇÃO À PROGRAMAÇÃO PROLOG

Tipologia: Notas de estudo

Antes de 2010

Compartilhado em 24/04/2009

emanuel-messias-ramos-7
emanuel-messias-ramos-7 🇧🇷

2 documentos

1 / 198

Toggle sidebar

Esta página não é visível na pré-visualização

Não perca as partes importantes!

bg1
INTRODUÇÃO À PROGRAMAÇÃO
PROLOG
Luiz A. M. Palazzo
Editora da Universidade Católica de Pelotas / UCPEL
Rua Félix da Cunha, 412 - Fone (0532)22-1555 - Fax (0532)25-3105
Pelotas - RS - Brasil
EDUCAT
Editora da Universidade Católica de Pelotas
Pelotas, 1997
© 1997 LUIZ A. M. PALAZZO
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e
pf1f
pf20
pf21
pf22
pf23
pf24
pf25
pf26
pf27
pf28
pf29
pf2a
pf2b
pf2c
pf2d
pf2e
pf2f
pf30
pf31
pf32
pf33
pf34
pf35
pf36
pf37
pf38
pf39
pf3a
pf3b
pf3c
pf3d
pf3e
pf3f
pf40
pf41
pf42
pf43
pf44
pf45
pf46
pf47
pf48
pf49
pf4a
pf4b
pf4c
pf4d
pf4e
pf4f
pf50
pf51
pf52
pf53
pf54
pf55
pf56
pf57
pf58
pf59
pf5a
pf5b
pf5c
pf5d
pf5e
pf5f
pf60
pf61
pf62
pf63
pf64

Pré-visualização parcial do texto

Baixe Introdução à programação e outras Notas de estudo em PDF para Cultura, somente na Docsity!

INTRODUÇÃO À PROGRAMAÇÃO

PROLOG

Luiz A. M. Palazzo

Editora da Universidade Católica de Pelotas / UCPEL Rua Félix da Cunha, 412 - Fone (0532)22-1555 - Fax (0532)25- Pelotas - RS - Brasil EDUCAT Editora da Universidade Católica de Pelotas Pelotas, 1997 © 1997 LUIZ A. M. PALAZZO

SUMÁRIO

Tanto pelo privilégio da amizade de vários anos, como pela condição de colega profissional

do prof. Luiz Antonio Palazzo, já há muito acompanho sua contribuição à cultura em Ciência

da Computação na região em que trabalhamos (zona sul do Rio Grande do Sul). Com gradu-

ação e pós-graduação pela UFRGS, vem marcando sua atuação desde a época de estudante,

tanto no meio acadêmico como na comunidade em geral, por uma postura de vanguarda na

busca de tecnologias para um uso racional e eficiente da computação. Sem dúvida, este livro

permitirá que um número maior de pessoas se beneficiem de sua larga experiência no ofício

de ensinar.

A estrutura do livro mescla o contexto histórico da Inteligência Artificial (IA) com o estudo

do Prolog, uma das mais difundidas linguagens para Programação em Lógica. O conteúdo,

por sua vez, tem como ponto alto contemplar uma rigorosa conceituação formal, cujo empre-

go é caracterizado por exemplos claros e significativos.

O emprego das linguagens para Programação em Lógica ganhou significativo impulso com o

projeto Japonês de Sistemas Computacionais de Quinta Geração (1982-1992), o qual investi-

gou alternativas de hardware e software para atender o desenvolvimento de aplicações que

contemplavam metas ambiciosas, tais como reconhecimento de imagens, processamento da

linguagem natural, processamento de conhecimento, etc.

As linguagens para Programação em Lógica, a exemplo do Prolog, outrora empregadas

principalmente na prototipação, já podem ser utilizadas para resolver, com bom desempenho,

complexos problemas reais de IA. Isto se tornou possível pela disponibilidade de processado-

res poderosos a custos reduzidos, bem como pela disseminação do uso de arquiteturas para-

lelas.

Neste trabalho são ressaltadas, com muita propriedade, as vantagens do emprego da lógica

clausal para programação de computadores, resgatando a "elegância" das linguagens para

Programação em Lógica, nas quais o programador tem como principal preocupação a espe-

cificação em Prolog do problema a ser resolvido, ficando a cargo do sistema computacional

a gerência dos mecanismos de busca das possíveis soluções.

Esta obra moderna, das poucas em português no seu estilo, vem preencher uma lacuna edito-

rial, trazendo a estudantes e profissionais da ciência da computação uma abordagem ampla,

porém não menos crítica e objetiva, das perspectivas do uso da Programação em Lógica.

Adenauer Corrêa Yamin Pelotas, RS

1. LÓGICA E PROGRAMAÇÃO DE COMPUTADORES

A lógica é a ciência do pensamento correto^1. Esta declaração não implica contudo em afirmar que ela seja a ciência da verdade. Mesmo que tudo o que se permita afirmar dentro da lógica seja suposta- mente verdadeiro em determinado contexto, as mesmas afirmações podem resultar falsas se aplicadas ao mundo real. Os filósofos da lógica afirmam que, "para entender o que realmente acontece no mun- do, precisamos entender o que não acontece" , isto é, as propriedades invariantes das entidades ou objetos que o compõem. Com essa idéia em mente, podemos considerar lógicos os conjuntos de de- clarações que possuem a propriedade de ser verdadeiros ou falsos independentemente do tempo ou lugar que ocupam no universo considerado. Este insigth inicial costuma ser de grande valia para en- tender como a lógica pode ser empregada na programação de computadores com grande vantagem sobre as linguagens convencionais. O cálculo proposicional, que é o subconjunto da lógica matemáti- ca mais diretamente envolvido nesse processo, formaliza a estrutura lógica mais elementar do discurso definindo precisamente o significado dos conetivos e, ou, não, se...então e outros. No presente capí- tulo esboça-se a forma como evoluiu a idéia de empregar a lógica como linguagem de programação de computadores, comenta-se os principais usos e aplicações das linguagens baseadas na lógica, relata-se os resultados mais significativos obtidos ao longo dos dez anos do controvertido projeto japonês para o desenvolvimento dos denominados "Computadores de Quinta Geração" e, por fim, se tenta antecipar as perspectivas mais promissoras da pesquisa neste ramo do conhecimento científico.

1.1 AS RAÍZES

O uso da lógica na representação dos processos de raciocínio remonta aos estudos de Boole (1815-

  1. e de De Morgan (1806-1871), sobre o que veio a ser mais tarde chamado "Álgebra de Boole". Como o próprio nome indica, esses trabalhos estavam mais próximos de outras teorias matemáticas do que propriamente da lógica. Deve-se ao matemático alemão Göttlob Frege no seu "Begriffsschrift" (1879) a primeira versão do que hoje denominamos cálculo de predicados, proposto por ele como uma ferramenta para formalizar princípios lógicos. Esse sistema oferecia uma notação rica e consistente que Frege pretendia adequada para a representação de todos os conceitos matemáticos e para a for- malização exata do raciocínio dedutivo sobre tais conceitos, o que, afinal, acabou acontecendo.

No final do século passado a matemática havia atingido um estágio de desenvolvimento mais do que propício à exploração do novo instrumento proposto por Frege. Os matemáticos estavam abertos a novas áreas de pesquisa que demandavam profundo entendimento lógico assim como procedimentos sistemáticos de prova de teoremas mais poderosos e eficientes do que os até então empregados. Al- guns dos trabalhos mais significativos deste período foram a reconstrução axiomática da geometria abstrata por David Hilbert, a aritimética proposta por Giuseppe Peano e a exploração intuitiva da teo- ria geral dos conjuntos, por Georg Cantor, que também produziu a iluminada teoria dos números transfinitos. O relacionamento entre lógica e matemática foi profundamente investigado por Alfred North Whitehead e Bertrand Russel, que em "Principia Mathematica" (1910) demonstraram ser a ló- gica um instrumento adequado para a representação formal de grande parte da matemática.

Um passo muito importante foi dado em 1930, em estudos simultâneos, porém independentes, reali- zados pelo alemão Kurt Gödel e o francês Jacques Herbrand. Ambos, em suas dissertações de douto- rado, demonstraram que o mecanismo de prova do cálculo de predicados poderia oferecer uma prova formal de toda proposição logicamente verdadeira. O resultado de maior impacto foi entretanto pro- duzido por Gödel, em 1931, com a descoberta do "teorema da incompleteza dos sistemas de formali- zação da aritmética". A prova deste teorema se baseava nos denominados paradoxos de auto- referência (declarações do tipo: "Esta sentença é falsa", que não podem ser provadas nem verdadeiras

(^1) Na realidade, de uma certa classe de pensamento correto.

da execução para ser exercido pelo sistema de programação em lógica utilizado. Em outras palavras, a tarefa do programador passa a ser simplesmente a especificação do problema que deve ser soluciona- do, razão pela qual as linguagens lógicas podem ser vistas simultaneamente como linguagens para especificação formal e linguagens para a programação de computadores.

Um programa em lógica é então a representação de determinado problema ou situação expressa atra- vés de um conjunto finito de um tipo especial de sentenças lógicas denominadas cláusulas. Ao contrá- rio de programas em Pascal ou C, um programa em lógica não é a descrição de um procedimento para se obter a solução de um problema. Na realidade o sistema utilizado no processamento de programas em lógica é inteiramente responsável pelo procedimento a ser adotado na sua execução. Um programa em lógica pode também ser visto alternativamente como uma base de dados, exceto que as bases de dados convencionais descrevem apenas fatos tais como "Oscar é um avestruz", enquanto que as sen- tenças de um programa em lógica possuem um alcance mais genérico, permitindo a representação de regras como em "Todo avestruz é um pássaro", o que não possui correspondência em bases de dados convencionais. Na figura abaixo se procura explicitar as principais diferenças entre programação con- vencional e programação em lógica.

PROGRAMAS CONVENCIONAIS PROGRAMAS EM LÓGICA

Processamento Numérico Processamento Simbólico Soluções Algorítmicas Soluções Heurísticas Estruturas de Controle e Conhecimento Integradas Estruturas de Controle e Conhecimento Separadas Difícil Modificação Fácil Modificação Somente Respostas Totalmente Corretas Incluem Respostas Parcialmente Corretas Somente a Melhor Solução Possível Incluem Todas as Soluções Possíveis Figura 1.1 Programas Convencionais x Programas em Lógica

O paradigma fundamental da programação em lógica é o da programação declarativa , em oposição à programação procedimental típica das linguagens convencionais. A programação declarativa engloba também a programação funcional, cujo exemplo mais conhecido é a linguagem Lisp. Lembrando en- tretanto que Lisp data de 1960, a programação funcional é um estilo conhecido há bastante tempo, ao contrário da programação em lógica, que só ganhou ímpeto a partir dos anos 80, quando foi escolhida como a linguagem básica do projeto japonês para o desenvolvimento dos denominados computadores de quinta geração. O ponto focal da programação em lógica consiste em identificar a noção de com- putação com a noção de dedução. Mais precisamente, os sistemas de programação em lógica reduzem a execução de programas à pesquisa da refutação das sentenças do programa em conjunto com a ne- gação da sentença que expressa a consulta, seguindo a regra: "uma refutação é a dedução de uma contradição".

Pode-se então expressar conhecimento (programas e/ou dados) em Prolog por meio de cláusulas de

dois tipos: fatos e regras^2. Um fato denota uma verdade incondicional, enquanto que as regras defi- nem as condições que devem ser satisfeitas para que uma certa declaração seja considerada verdadei- ra. Como fatos e regras podem ser utilizados conjuntamente, nenhum componente dedutivo adicional precisa ser utilizado. Além disso, como regras recursivas e não-determinismo são permitidos, os pro- gramadores podem obter descrições muito claras, concisas e não-redundantes da informação que de- sejam representar. Como não há distinção entre argumentos de entrada e de saída, qualquer combina- ção de argumentos pode ser empregada.

Os termos "programação em lógica" e "programação Prolog" tendem a ser empregados indistinta- mente. Deve-se, entretanto, destacar que a linguagem Prolog é apenas uma particular abordagem da programação em lógica. As características mais marcantes dos sistemas de programação em lógica em geral - e da linguagem Prolog em particular - são as seguintes:

(^2) Ver o Apêndice A para uma abordagem mais formal.

  • Especificações são Programas: A linguagem de especificação é entendida pela máquina e é, por si só, uma linguagem de programação. Naturalmente, o refinamento de especificações é mais efetivo do que o refinamento de programas. Um número ilimitado de cláusulas diferentes pode ser usado e predicados (procedimentos) com qualquer número de argumentos são possí- veis. Não há distinção entre o programa e os dados. As cláusulas podem ser usadas com grande vantagem sobre as construções convencionais para a representação de tipos abstratos de dados. A adequação da lógica para a representação simultânea de programas e suas especificações a torna um instrumento especialmente útil para o desenvolvimento de ambientes e protótipos.
  • Capacidade Dedutiva: O conceito de computação confunde-se com o de (passo de) inferência. A execução de um programa é a prova do teorema representado pela consulta formulada, com base nos axiomas representados pelas cláusulas (fatos e regras) do programa.
  • Não-determinismo: Os procedimentos podem apresentar múltiplas respostas, da mesma forma que podem solucionar múltiplas e aleatoriamente variáveis condições de entrada. Através de um mecanismo especial, denominado "backtracking", uma seqüência de resultados alternativos pode ser obtida.
  • Reversibilidade das Relações: (Ou "computação bidirecional"). Os argumentos de um proce- dimento podem alternativamente, em diferentes chamadas representar ora parâmetros de entra- da, ora de saída. Os procedimentos podem assim ser projetados para atender a múltiplos propó- sitos. A execução pode ocorrer em qualquer sentido, dependendo do contexto. Por exemplo, o mesmo procedimento para inserir um elemento no topo de uma pilha qualquer pode ser usado, em sentido contrário, para remover o elemento que se encontrar no topo desta pilha.
  • Tríplice Interpretação dos Programas em Lógica: Um programa em lógica pode ser seman- ticamente interpretado de três modos distintos: (1) por meio da semântica declarativa, inerente à lógica, (2) por meio da semântica procedimental, onde as cláusulas dos programas são vistas como entrada para um método de prova e, (3) por meio da semântica operacional, onde as cláu- sulas são vistas como comandos para um procedimento particular de prova por refutação. Essas três interpretações são intercambiáveis segundo a particular abordagem que se mostrar mais vantajosa ao problema que se tenta solucionar.
  • Recursão: A recursão, em Prolog, é a forma natural de ver e representar dados e programas. Entretanto, na sintaxe da linguagem não há laços do tipo "for" ou "while" (apesar de poderem ser facilmente programados), simplesmente porque eles são absolutamente desnecessários. Também são dispensados comandos de atribuição e, evidentemente, o "goto". Uma estrutura de dados contendo variáveis livres pode ser retornada como a saída de um procedimento. Essas va- riáveis livres podem ser posteriormente instanciadas por outros procedimentos produzindo o efeito de atribuições implícitas a estruturas de dados. Onde for necessário, variáveis livres são automaticamente agrupadas por meio de referências transparentes ao programador. Assim, as variáveis lógicas um potencial de representação significativamente maior do que oferecido por operações de atribuição e referência nas linguagens convencionais.

A premissa básica da programação em lógica é portanto que "computação é inferência controlada". Tal visão da computação tem se mostrado extremamente produtiva, na medida em que conduz à idéia de que computadores podem ser projetados com a arquitetura de máquinas de inferência. Grande parte da pesquisa sobre computação paralela, conduzida hoje nos EUA, Europa e Japão, emprega a progra- mação em lógica como instrumento básico para a especificação de novas arquiteturas de hardware e o desenvolvimento de máquinas abstratas não-convencionais.

1.3 APLICAÇÕES

Um dos primeiros usos da programação em lógica foi a representação e análise de subconjuntos da linguagem natural. Esta foi inclusive a aplicação que motivou Alain Colmerauer a desenvolver a pri-

tões sobre a estrutura de sentenças em linguagem natural fossem formuladas como objetivos ao sistema, e (3) que diferentes procedimentos de prova aplicados a representações lógicas da lin- guagem natural correspondiam a diferentes estratégias de análise.

  • Educação: A programação em lógica poderá vir a oferecer no futuro uma contribuição bastante significativa ao uso educacional de computadores. Esta proposta foi testada em 1978 quando Kowalski introduziu a programação em lógica na Park House Middle School em Wimbledon, na Inglaterra, usando acesso on-line aos computadores do Imperial College. O sucesso do em- preendimento conduziu a um projeto mais abrangente denominado "Lógica como Linguagem de Programação para Crianças", inaugurado em 1980 na Inglaterra com recursos do Conselho de Pesquisa Científica daquele país. Os resultados obtidos desde então tem mostrado que a pro- gramação em lógica não somente é assimilada mais facilmente do que as linguagens convenci- onais, como também pode ser introduzida até mesmo a crianças na faixa dos 10 a 12 anos, as quais ainda se beneficiam do desenvolvimento do pensamento lógico-formal que o uso de lin- guagens como o Prolog induz.
  • Arquiteturas Não-Convencionais: Esta área vem se tornando cada vez mais um campo extre- mamente fértil para o uso da programação em lógica especialmente na especificação e imple- mentação de máquinas abstratas de processamento paralelo. O paralelismo pode ser modelado pela programação em lógica em variados graus de atividade se implementado em conjunto com o mecanismo de unificação. Duas implementações iniciais nesse sentido foram o Parlog , des- envolvido em 1984 por Clark e Gregory, e o Concurrent Prolog (CP), por Shapiro em 1983. O projeto da Quinta Geração, introduzido na próxima seção, foi fortemente orientado ao uso da programação em lógica em sistemas de processamento paralelo.

Muitas outras aplicações poderiam ainda ser citadas, principalmente na área da inteligência artificial, que tem no Prolog e no Lisp as suas duas linguagens mais importantes. Novas tecnologias de hardwa- re e software tais como sistemas massivamente paralelos, redes de computadores, assistentes inteli- gentes, bases de dados semânticas, etc., tornam o uso do Prolog (e de outras linguagens baseadas em lógica) cada vez mais atraentes

1.4 A QUINTA GERAÇÃO

Em 1979 o governo japonês iniciou estudos para um novo, ambicioso e único projeto na área da com- putação normalmente denominado Sistemas Computacionais de Quinta Geração cujo objetivo princi- pal era o desenvolvimento, no espaço de uma década, de hardware e software de alto desempenho, caracterizando uma nova geração de computadores. O projeto iniciou em 1982 e foi oficialmente en- cerrado em maio de 1992. Muito foi dito e escrito sobre o projeto, que produziu inúmeros resultados e diversos subprodutos ao longo desses dez anos. Um de seus principais méritos, entretanto, parece ter sido chamar a atenção da comunidade científica mundial para as potencialidades da lógica como lin- guagem de programação de computadores. Sistemas de processamento lógico paralelo derivados do Prolog foram desenvolvidos para servir como linguagens-núcleo (kernel languages) dos novos equi- pamentos que seriam produzidos a partir dos resultados do projeto. Considerado um sucesso por seus dirigentes, o projeto foi entretanto criticado por não haver conseguido colocar as tecnologias desen- volvidas à disposição do grande público. Em outras palavras: ainda não dispomos hoje (1994) de mi- crocomputadores pessoais de quinta geração - denominados máquinas PSI (Personal Sequential Infe- rence machines) - comercialmente viáveis para o grande público. Os resultados teóricos obtidos e os protótipos construídos foram entretanto de grande valia para que num futuro próximo isso venha a ser possível. Nestas novas máquinas o papel da linguagem assembly será desempenhado por um dialeto do Prolog orientado ao processamento paralelo.

Um relatório sobre o projeto, organizado por Ehud Shapiro e David Warren em 1993, reuniu as opini- ões de diversos pesquisadores dele participantes, entre os quais Kazuhiro Fuchi, seu líder, Robert Kowalski, Koichi Furukawa, Kazunori Ueda e outros. Todos os depoimentos foram unânimes em

declarar que os objetivos do projeto foram plenamente atingidos. Na Figura 1.2 é mostrada uma adaptação em português do diagrama "de intenções" apresentado por Fuchi, no Fifth Generation Computer Systems Congress de 1981 (FGCS'81), o congresso que deu a conhecer ao mundo um dos mais ambiciosos projetos da história da computação.

ANO 1 ANO 5 ANO 10

 Network --- Ótica ---

 Personal Inference Machine (Redução a chips)

Máquina Prolog + 

(Novo Software) LISPAPL Smalltalk PS, etc.

Programação: em lógica e funcional

(comparáveis às máquinas de grande porte de 1981)

 Ambientes de Programação Inteligentes  Ambientes de Projeto Orientados à Prototipagem  Máquinas Altamente Configuráveis (Chips e Módulos)  Supermáquinas (Realmente Inteligentes)

Nova Linguagem

5G Core Language

(INFERENCE MACHINE)

Data Flow Machine

Database Machine

Paralelismo

Associatividade

 SOFTWARE -----------> Engenharia de Conhecimento (Acumulação) ---------------------------------------------------------> Engenharia de Software (Teorias Básicas) Pesquisa em Inteligência Artificial

Solução de Problemas: Bases de Conhecimento:

Simbolismo em Alto Nível: Planejamento Programação Prova de Teoremas Jogos

Entendimento da Linguagem Natural Consultas

Figura 1.2 Diagrama Conceitual do Projeto do Computador de Quinta Geração

Segundo o relatório de Shapiro e Warren, um dos primeiros passos do projeto consistiu em definir uma linguagem de programação em lógica que ao mesmo tempo fosse adequada ao paralelismo do hardware e aos requisitos sofisticados especificados para o software. Baseada no Parlog e no Cuncur- rent Prolog, uma equipe de pesquisadores liderada por Kazunori Ueda desenvolveu a linguagem GHC (Guarded Horn Clauses), que deu origem à KL0 (Kernel Language Zero). Um refinamento dessa ver-

são beta^4 , realizado pela equipe de Takashi Chikayama produziu, em 1987, a linguagem KL1. Todos os sub-projetos do FGCS foram revistos para trabalhar com essa linguagem. Em 1988 os primeiros protótipos do computador de quinta geração foram construídos, recebendo o nome genérico de Pa- rallel Inference Machines (PIMs). Tais computadores possuiam arquitetura massivamente paralela e tinham velocidade de processamento calculada em MLIPS (milhões de inferências lógicas por segun- do). Uma dessas máquinas, denominada Multi-PSI foi apresentada com grande sucesso no FGCS'88.

(^4) Uma versão distribuida a grupos selecionados de usuários para teste e depuração.

que, entre outras vantagens:

(1) É de aprendizado muito mais fácil e natural do que as linguagens procedimentais convencio- nais, podendo inclusive ser ministrada a estudantes entre o final do primeiro e o início do se- gundo grau com grande aproveitamento; (2) Implementa com precisão todos os novos modelos surgidos nos últimos anos, inclusive redes neurais, algoritmos genéticos, sociedades de agentes inteligentes, sistemas concorrentes e pa- ralelos; (3) Permite a implementação de extensões, inclusive em nível meta , e a definição precisa de siste- mas reflexivos (essenciais, por exemplo, à robótica); (4) Libera o programador dos problemas associados ao controle de suas rotinas , permitindo-lhe concentrar-se nos aspectos lógicos da situação a representar.

Tem sido observada a tendência de substituição paulatina no mercado de trabalho dos serviços de programação pelos de especificação. Isso ocorre por várias razões, dentre elas porque as especifica- ções podem ser formalmente provadas corretas, o que não ocorre com facilidade nos programas con- vencionais. Essa transição - da arte de programar à ciência de especificar - vem estimulando o apare- cimento de linguagens como o Prolog, que pode ser visto como sendo simultaneamente uma lingua- gem de programação e de especificação (ou, como querem alguns, como uma linguagem de especifi- cações diretamente executáveis em computadores).

Vem também ocorrendo aceleradamente a popularização de ambientes e interfaces cada vez mais próximos do usuário final e oferecendo recursos muito poderosos para a personalização de programas de acordo com as preferências individuais. Isso permite supor que, num futuro próximo, qualquer pessoa, mesmo sem formação específica em programação, poderá interagir facilmente com computa-

dores, em níveis muito elevados^7 , dispensando em grande parte a programação, tal como é hoje co- nhecida. Por outro lado, a construção de tais ambientes ira depender de profissionais bem mais prepa- rados do que um programador em Pascal, por exemplo. Deverão, tais profissionais, possuir um currí- culo muito mais rico, abrangendo a teoria da computação, lógica matemática, álgebra relacional, filo- sofia, arquiteturas concorrentes e paralelas, etc. Serão necessários entretanto em número muito maior do que se imaginava no início dos anos 80, quando essa tendência ainda não se apresentava perfeita- mente delineada, uma vez que praticamente todo software colocado no mercado deverá ser produzido a partir de suas especificações formais.

Um último motivo - não menos importante que os demais já apresentados - deve ainda ser considera- do: A expressividade herdada da lógica torna a linguagem Prolog um instrumento especialmente po- deroso, adequado para a descrição do mundo real com todos os seus contornos, nuances e sutilezas. Nos poucos casos em que a representação se torna mais difícil - na representação temporal, por exem- plo - a flexibilidade do Prolog em aceitar o desenvolvimento de extensões semanticamente precisas e incorporá-las ao seu mecanismo de produção de inferências, remove qualquer impedimento para o seu emprego em virtualmente qualquer área do conhecimento.

RESUMO

  • A programação em lógica, tal como a conhecemos hoje, tem suas raízes no cálculo de predica- dos, proposto por Frege em 1879. Diversos estudos posteriores foram de grande importância para sua evolução, com destaque para as investigações de Herbrand, Gödel, Tarski, Prawitz, Robinson e Green;
  • A primeira implementação da linguagem Prolog foi realizada por Alain Colmerauer e sua equi-

(^7) Ao nível da linguagem coloquial falada ou escrita, por exemplo.

pe, na Universidade de Aix-Marseille em 1972. A formalização semântica da programação com cláusulas de Horn é devida a Kowalski (1974) e a especificação do primeiro "standard" - o Prolog de Edimburgo - foi realizada por Warren e Pereira em 1977;

  • As principais características que diferenciam os programas em lógica dos programas convenci- onais são as seguintes: (1) Processamento simbólico, (2) Soluções heurísticas, (3) Estruturas de controle e conhecimento separadas, (4) Fácil modificação, (5) Incluem respostas parcialmente corretas, e (6) Incluem todas as soluções possíveis;
  • Além disso, os sistemas de programação em lógica em geral e a linguagem Prolog em particular possuem as seguintes propriedades: (1) Funcionam simultaneamente como linguagem de programação e de especificação, (2) Possuem capacidade dedutiva, (3) Operam de forma não-determinística, (4) Permitem a representação de relações reversíveis, (5) Permitem interpretação declarativa, procedimental e operacional, e (6) São naturalmente recursivos;
  • As principais aplicação da programação em lógica são: (1) Sistemas Baseados em Conhecimento SBCs), (2) Sistemas de Bases de Dados (BDs), (3) Sistemas Especialistas (SEs), (4) Processamento da Linguagem Natural (PLN), (5) Educação, e (6) Modelagem de Arquiteturas Não-Convencionais;
  • O projeto japonês para o desenvolvimento de Sistemas Computacionais de Quinta Geração ini- ciou em 1982 e foi oficialmente concluído em maio de 1992. Apesar de ficarem aquém do espe- rado, os resultados produzidos permitem claramente antever o papel preponderante que a pro- gramação em lógica deverá representar nos futuros sistemas computacionais;
  • A crescente necessidade de garantir a qualidade do software substituindo programas por especi- ficações formais diretamente executáveis, aliada à evolução das características do hardware, que passam a explorar cada vez mais os conceitos de concorrência e paralelismo, tornam a lin- guagem Prolog uma excelente porta de entrada para a informática do futuro.

José é o progenitor de Íris, o sistema responde "sim".

?-progenitor(josé, íris). sim

Maria João

José Ana

Júlia Íris

Jorge

Figura 2.1 Uma árvore genealógica

Uma outra questão poderia ser: "Ana é um dos progenitores de Jorge?". Nesse caso o sistema respon- de "não", porque não há nenhuma cláusula no programa que permita deduzir tal fato.

?-progenitor(ana, jorge). não

A questão "Luís é progenitor de Maria?" também obteria a resposta "não" , porque o programa nem sequer conhece alguém com o nome Luís.

?-progenitor(luís, maria). não

Perguntas mais interessantes podem também ser formuladas, por exemplo: "Quem é progenitor de Íris?". Para fazer isso introduz-se uma variável, por exemplo "X" na posição do argumento corres- pondente ao progenitor de Íris. Desta feita o sistema não se limitará a responder "sim" ou "não", mas irá procurar (e informar caso for encontrado) um valor de X que torne a assertiva "X é progenitor de Íris" verdadeira.

?-progenitor(X, íris). X=josé

Da mesma forma a questão "Quem são os filhos de José?" pode ser formulada com a introdução de uma variável na posição do argumento correspondente ao filhos de José. Note que, neste caso, mais de uma resposta verdadeira pode ser encontrada. O sistema irá fornecer a primeira que encontrar e aguardar manifestação por parte do usuário. Se este desejar outras soluções deve digitar um ponto-e- vírgula (;), do contrário digita um ponto (.), o que informa ao sistema que a solução fornecida é sufi- ciente.

?-progenitor(josé, X). X=júlia; X=íris; não

Aqui a última resposta obtida foi "não" significando que todas as soluções válidas já foram forneci- das. Uma questão mais geral para o programa seria: "Quem é progenitor de quem?" ou, com outra formulação: "Encontre X e Y tal que X é progenitor de Y". O sistema, em resposta, irá fornecer (en- quanto se desejar, digitando ";") todos os pares progenitor-filho até que estes se esgotem (quando então responde "não") ou até que se resolva encerrar a apresentação de novas soluções (digitando "."). No exemplo a seguir iremos nos satisfazer com as três primeiras soluções encontradas.

?-progenitor(X, Y).

X=maria Y=josé; X=joão Y=josé; X=joão Y=ana.

Pode-se formular questões ainda mais complicadas ao programa, como "Quem são os avós de Jor- ge?". Como nosso programa não possui diretamente a relação avô , esta consulta precisa ser dividida em duas etapas, como pode ser visto na Figura 2.2. A saber:

(1) Quem é progenitor de Jorge? (Por exemplo, Y) e (2) Quem é progenitor de Y? (Por exemplo, X)

Esta consulta em Prolog é escrita como uma seqüência de duas consultas simples, cuja leitura pode ser: "Encontre X e Y tais que X é progenitor de Y e Y é progenitor de Jorge".

?-progenitor(X, Y), progenitor(Y, jorge). X=josé Y=íris

X

Y

Jorge

progenitor

progenitor

avô

Figura 2.2 A relação avô em função de progenitor

Observe que se mudarmos a ordem das consultas na composição, o significado lógico permanece o mesmo, apesar do resultado ser informado na ordem inversa:

?-progenitor(Y, jorge), progenitor(X, Y). Y=íris X=josé

De modo similar podemos perguntar: "Quem é neto de João?" :

?-progenitor(joão, X), progenitor(X, Y). X=josé Y=júlia; X=josé Y=íris.

Ainda uma outra pergunta poderia ser: "José e Ana possuem algum progenitor em comum?". Nova- mente é necessário decompor a questão em duas etapas, formulando-a alternativamente como: "En- contre um X tal que X seja simultaneamente progenitor de José e Ana".

?-progenitor(X, josé), progenitor(X, ana). X=joão

Por meio dos exemplos apresentados até aqui acredita-se ter sido possível ilustrar os seguintes pontos:

  • Uma relação como progenitor pode ser facilmente definida em Prolog estabelecendo-se as tu- plas de objetos que satisfazem a relação;
  • O usuário pode facilmente consultar o sistema Prolog sobre as relações definidas em seu pro- grama;
  • Um programa Prolog é constituído de cláusulas , cada uma das quais é encerrada por um ponto (.);
  • Os argumentos das relações podem ser objetos concretos (como júlia e íris) ou objetos genéri- cos (como X e Y). Objetos concretos em um programa são denominados átomos, enquanto que os objetos genéricos são denominados variáveis ;
  • Uma parte de condição (o lado direito da cláusula).

O símbolo ":-" significa "se" e separa a cláusula em conclusão, ou cabeça da cláusula, e condição ou corpo da cláusula, como é mostrado no esquema abaixo. Se a condição expressa pelo corpo da cláu- sula - progenitor (X, Y) - é verdadeira então, segue como conseqüência lógica que a cabeça - filho(Y, X) - também o é. Por outro lado, se não for possível demonstrar que o corpo da cláusula é verdadeiro, o mesmo irá se aplicar à cabeça.

filho(Y, X) :- progenitor(X, Y)

A maioria dos sistemas Prolog, na ausência de caracteres ASCII adequados, emprega o símbolo com- posto ":-" para denotar a implicação "¬". Aqui, por uma questão de clareza, adotaremos este último símbolo, que é o normalmente empregado na programação em lógica com cláusulas definidas.

A utilização das regras pelo sistema Prolog é ilustrada pelo seguinte exemplo: vamos perguntar ao programa se José é filho de Maria:

?-filho(josé, maria).

Não há nenhum fato a esse respeito no programa, portanto a única forma de considerar esta questão é aplicando a regra correspondente. A regra é genérica, no sentido de ser aplicável a quaisquer objetos X e Y. Logo pode ser aplicada a objetos particulares, como josé e maria. Para aplicar a regra, Y será substituído por josé e X por maria. Dizemos que as variáveis X e Y se tornaram instanciadas para:

X=maria e Y=josé

A parte de condição se transformou então no objetivo progenitor(maria, josé). Em seguida o sistema passa a tentar verificar se essa condição é verdadeira. Assim o objetivo inicial, filho(josé, maria) , foi substituído pelo sub-objetivo progenitor(maria, josé). Esse novo objetivo apresenta-se como trivial, uma vez que há um fato no programa estabelecendo exatamente que Maria é um dos progenitores de José. Isso significa que a parte de condição da regra é verdadeira, portanto a parte de conclusão tam- bém é verdadeira e o sistema responde "sim".

Vamos agora adicionar mais algumas relações ao nosso programa. A especificação, por exemplo, da relação mãe entre dois objetos do nosso domínio pode ser escrita baseada na seguinte declaração lógi- ca:

Para todo X e Y X é mãe de Y se X é progenitor de Y e X é feminino.

que, traduzida para Prolog, conduz à seguinte regra:

mãe(X, Y) :- progenitor(X, Y), feminino(X).

onde a vírgula entre as duas condições indica a sua conjunção , significando que, para satisfazer o corpo da regra, ambas as condições devem ser verdadeiras. A relação avô, apresentada anteriormente na Figura 2.2, pode agora ser definida em Prolog por:

avô(X, Z) :- progenitor(X, Y), progenitor(Y, Z).

Neste ponto é interessante comentar alguma coisa sobre o layout dos programas Prolog. Estes podem ser escritos quase que com total liberdade, de modo que podemos inserir espaços e mudar de linha onde e quando melhor nos aprouver. Em geral, porém, desejamos produzir programas de boa aparên- cia, elegantes e sobretudo fáceis de ser lidos. Com essa finalidade, normalmente se prefere escrever a cabeça da cláusula e os objetivos da condição cada um em uma nova linha. Para destacar a conclusão, identamos os objetivos. A cláusula avô, por exemplo, seria escrita:

avô(X, Z) :- progenitor(X, Y), progenitor(Y, Z).

Adicionaremos ainda uma última relação ao nosso programa para exemplificar mais uma particulari- dade da linguagem Prolog. Uma cláusula para a relação irmã se embasaria na seguinte declaração lógica:

Para todo X e Y X é irmã de Y se X e Y possuem um progenitor comum e X é do sexo feminino.

Ou, sob a forma de regra Prolog:

irmã(X, Y) :- progenitor(Z, X), progenitor(Z, Y), feminino(X).

Deve-se atentar para a forma sob a qual o requisito "X e Y possuem um progenitor comum" foi expres- sa. A seguinte formulação lógica foi adotada: "Algum Z deve ser progenitor de X e esse mesmo Z deve também ser progenitor de Y". Uma forma alternativa, porém menos elegante, de representar a mesma condição seria: "Z1 é progenitor de X e Z2 é progenitor de Y e Z1 é igual a Z2". Se consultarmos o sistema com "Júlia é irmã de Íris?" , obteremos, como é esperado, um "sim" como resposta. Podería- mos então concluir que a relação irmã , conforme anteriormente definida, funciona corretamente, en- tretanto, há uma falha muito sutil que se revela quando perguntamos: "Quem é irmã de Íris?". O sis- tema irá nos fornecer duas respostas:

?-irmã(X, íris). X=júlia; X=íris

dando a entender que Íris é irmã de si própria. Isso não é certamente o que se tinha em mente na defi- nição de irmã , entretanto, de acordo com a regra formulada, a resposta obtida pelo sistema é perfeita- mente lógica. Nossa regra sobre irmãs não menciona que X e Y não devem ser os mesmos para que X seja irmã de Y. Como isso não foi requerido, o sistema, com toda razão, assume que X e Y podem denotar a mesma pessoa e irá achar que toda pessoa do sexo feminino que possui um progenitor é irmã de si própria.

Para corrigir esta distorção é necessário acrescentar a condição de que X e Y devem ser diferentes. Isso pode ser feito de diversas maneiras, conforme se verá mais adiante. Por enquanto vamos assumir que uma relação diferente(X, Y) seja reconhecida pelo sistema como verdadeira se e somente se X e Y não forem iguais. A regra para a relação irmã fica então definida por:

irmã(X, Y) :- progenitor(Z, X), progenitor(Z,Y), feminino(X), diferente(X, Y).

Os pontos mais importantes vistos na presente seção foram:

  • Programas Prolog podem ser ampliados pela simples adição de novas cláusulas;
  • As cláusulas Prolog podem ser de três tipos distintos: fatos, regras e consultas;
  • Os fatos declaram coisas que são incondicionalmente verdadeiras;
  • As regras declaram coisas que podem ser ou não verdadeiras, dependendo da satisfação das condições dadas;
  • Por meio de consultas podemos interrogar o programa acerca de que coisas são verdadeiras;
  • As cláusulas Prolog são constituídas por uma cabeça e um corpo. O corpo é uma lista de objeti- vos separados por vírgulas que devem ser interpretadas como conjunções;
  • Fatos são cláusulas que só possuem cabeça, enquanto que as consultas só possuem corpo e as regras possuem cabeça e corpo;