Curso de ScriptVox Intermediário - Aula 14 - Prof. Oswaldo Vernet - iNCE/UFRJ

Para esta aula, baixem a nova versão do interpretador.

Já na primeira aula, uma importante melhoria da versão 6.0 do ScriptVox foi apresentada:
as expressões. Vimos que uma expressão é uma sentença que envolve operandos e operadores.
No momento da avaliação de uma expressão, os operandos resultam em valores e, a estes valores,
os operadores são aplicados, respeitada a precedência, até que o valor final resultante da
avaliação é obtido.

Naquele momento, dispúnhamos apenas dos tipos inteiro e cadeia e todos os nossos exemplos
basearam-se em operandos destes dois tipos. Agora que já estudamos o tipo lista, cumpre
retornar ao estudo das expressões e introduzir os operadores que se aplicam a operandos
deste tipo.

O operador "+" aplica-se, em princípio, a operandos inteiros; a sobrecarga para o
tipo cadeia modifica a semântica deste operador, que passa a significar concatenação.
Em alguns exemplos, examinamos o efeito deste operador em expressões mistas, envolvendo
um operando inteiro e outro cadeia. Nestas expressões, ocorrem conversões entre tipos,
a fim de que a aplicação do operador seja sempre possível.

O operador "+" é também sobrecarregado para o tipo lista, significando concatenação.
Concatenar duas listas produz como resultado também uma lista, cuja cardinalidade é
a soma das cardinalidades das duas. Os elementos desta lista resultante são os elementos
da lista mencionada à esquerda do operador "+" seguidos dos elementos da lista mencionada
à direta. O seguinte exemplo ilustra a concatenação entre listas:

cores := [ "amarelo", "azul", "laranja", "verde" ]
todas_as_cores := cores + [ "violeta", "verde", "púrpura", "ocre", "grená" ]

O operador "+" está aplicado, neste exemplo, a duas listas: a primeira está armazenada
na variável "cores" e a segunda é definida explicitamente mediante a enumeração de seus
elementos. O valor final armazenado na variável "todas_as_cores" será a lista:

[ "amarelo", "azul", "laranja", "verde", "violeta", "verde", "púrpura", "ocre", "grená" ]

Observe que a ordem dos elementos é respeitada na formação da lista resultante
da concatenação. O elemento "verde" aparece repetido, pois, na concatenação de listas,
nenhum elemento é perdido.

Um ponto importante a observar é que o operador de concatenação aplicado a listas espera
sempre duas listas como operandos. Portanto, não é válida a seguinte atribuição:

cores := cores + "roxo"

já que, neste exemplo, o operador à direita é uma cadeia e não uma lista. O resultado
desta expressão será inválido.

O operador "-", até agora, significa apenas subtração entre inteiros; ele não possui
sobrecarga para o tipo cadeia. Porém, aplicado a listas, este operador produz como
resultado também uma lista, constituída por todos os elementos da lista à esquerda
do operador que não aparecem na lista à direita do operador. Acompanhe o seguinte
exemplo:

cores := [ "amarelo", "azul", "laranja", "verde" ]
cores_feias := [ "roxo", "laranja", "lilás", "amarelo" ]
cores_belas := cores - cores_feias

A variável "cores_belas" armazenará o valor resultante da avaliação da expressão
situada à direita do símbolo de atribuição ":=", que consiste em uma diferença entre 
listas. A lista à esquerda do operador "-" é "cores" e possui em comum com a
lista "cores_feias", à direita, os elementos "laranja" e "amarelo", apenas. 
Portanto, o valor armazenado na variável "cores_belas" será a lista

[ "azul", "verde" ]

Observe que a ordem dos elementos na lista-diferença respeita a ordem dos elementos
na lista à esquerda do operador. Por isso, o elemento "azul" precede o elemento "verde".

O operador "*", até o momento, significa apenas multiplicação entre inteiros. 
Este operador também está sobrecarregado para o tipo lista, da seguinte forma:
a lista resultante conterá apenas os elementos comuns entre a lista à esquerda
e a lista à direita do operador. Analise o exemplo:

minhas_cores := [ "amarelo", "azul", "laranja", "verde" ]
cores_feias := [ "roxo", "laranja", "lilás", "amarelo" ]
suas_cores := minhas_cores * cores_feias

O valor final armazenado na variável "suas_cores" será a lista

[ "amarelo", "laranja" ]

já que estes são os elementos pertencentes simultaneamente às duas listas.
Observe, novamente, que a ordem dos elementos na lista resultante é ditada 
pela lista à esquerda do operador "*"; assim, "amarelo" deve preceder "laranja".

Não mencionamos ainda neste curso os três operadores de inclusão que se
aplicam ao tipo cadeia e que estão documentados no manual antigo do ScriptVox.
São eles:  "=*", "*=" e "*=*". Vamos analisar a sobrecarga desses operadores para
o tipo lista.

O operador "=*" é lido da seguinte maneira: "começa por". Aplicado a cadeias, 
ele produz o resultado verdadeiro (o inteiro um) ou falso (o inteiro zero),
conforme a cadeia à direita seja ou não um prefixo da cadeia à esquerda do operador.
A sobrecarga para listas preserva exatamente esta semântica. Siga o exemplo:

minhas_cores := [ "amarelo", "azul", "laranja", "verde" ]
se minhas_cores =* [ "amarelo", "azul" ]
	escreve "SIM"
senão
	escreve "NÃO"
fim se

Neste exemplo, a palavra SIM será escrita na tela, já que a lista à direita do
operador "=*" é um prefixo da lista à esquerda do operador.

O operador "*=" é lido da seguinte maneira: "termina por". Aplicado a cadeias, 
ele produz o resultado verdadeiro (o inteiro um) ou falso (o inteiro zero),
conforme a cadeia à direita seja ou não um sufixo da cadeia à esquerda do operador.
A sobrecarga para listas preserva exatamente esta semântica. Siga o exemplo:

minhas_cores := [ "amarelo", "azul", "laranja", "verde" ]
se minhas_cores *= [ "laranja", "verde" ]
	escreve "SIM"
senão
	escreve "NÃO"
fim se

Neste exemplo, também será escrita a palavra SIM na tela, pois a lista à direita do
operador "*=" é um sufixo da lista à esquerda do operador.

O operador "*=*" é lido da seguinte maneira: "contém". Aplicado a cadeias,
ele produz o resultado verdadeiro (o inteiro um) ou falso (o inteiro zero),
conforme a cadeia à direita seja ou não uma subcadeia da cadeia à esquerda do operador.
Aplicado a listas, preserva exatamente esta semântica. Assim como nas cadeias,
para ser considerada uma sublista da lista que aparece à esquerda do operador "*=*",
os elementos da lista à direita devem ocorrer todos sequencialmente a partir de alguma 
posição da lista à esquerda, na mesma ordem em que aparecem na lista à direita. 
Siga o exemplo:

minhas_cores := [ "amarelo", "azul", "laranja", "verde" ]
se minhas_cores *=* [ "azul", "laranja" ]
	escreve "SIM"
senão
	escreve "NÃO"
fim se

Porém, no exemplo seguinte:

minhas_cores := [ "amarelo", "azul", "laranja", "verde" ]
se minhas_cores *=* [ "laranja", "amarelo" ]
	escreve "SIM"
senão
	escreve "NÃO"
fim se

seria escrita a palavra NÃO na tela, pois, embora os elementos "laranja" e
"amarelo" pertençam à lista  [ "amarelo", "azul", "laranja", "verde" ], nem a
sequencialidade nem a ordem são respeitadas.


EXERCÍCIOS

Exercícios de Estudo Dirigido

1.  Utilizando os operadores vistos acima, mostre como introduzir um elemento na 
    posição zero de uma lista, sem usar a função INSERE.
2.  Mostre como anexar um elemento a uma lista usando o operador "+". 
3.  Os operadores "-" e "*", aplicados a listas, lembram de longe duas operações 
    sobre conjuntos que estudamos na matemática elementar. Quais são elas?
4.  Em que circunstâncias o operador "-", aplicado a duas listas, produzirá como
    resultado a lista vazia?
5.  Em que circunstâncias o operador "*", aplicado a duas listas, produzirá como
    resultado a lista vazia?
6.  Uma diferença essencial entre listas e conjuntos é que, nas listas, a ordem dos
    elementos é importante, ao passo que conjuntos não possuem qualquer ordem.
    Que outras diferenças você percebe entre listas e conjuntos?
7.  Sem usar a função POS, qual dos operadores acima estudados você escolheria para 
    verificar se um elemento pertence a uma lista?  Como você o usaria?  Dê um exemplo.
	

Exercício de avaliação (enviar para scriptvox@gmail.com até o meio-dia de 8 de março de 2012)

O objetivo deste exercício é implementar as operações sobre CONJUNTOS utilizando listas
em ScriptVox. Um conjunto será representado por uma lista na qual não podem existir elementos
repetidos.

Para cada uma das cinco operações discriminadas a seguir, você deverá escrever uma função:

1. PRODUZIR o conjunto vazio
   Esta operação não espera parâmetros e retorna, como resultado, o conjunto vazio.

2. VERIFICAR se um elemento pertence a um conjunto
   Esta operação espera dois parâmetros: o primeiro é um elemento e o segundo é um conjunto.
   Ela deve retornar verdadeiro (o inteiro um) se o elemento pertencer ao conjunto ou falso
   (o inteiro zero) se o elemento não pertencer ao conjunto.
   
3. Computar a UNIÃO entre dois conjuntos
   Esta operação recebe dois parâmetros, que são os conjuntos a serem unidos. 
   Ela deve retornar como resultado um conjunto, consistindo de todos os elementos que pertencem
   ao primeiro ou ao segundo conjunto.

4. Computar a INTERSEÇÃO entre dois conjuntos
   Esta operação recebe dois parâmetros, que são os conjuntos cuja interseção se deseja obter. 
   Ela deve retornar como resultado um conjunto, consistindo de todos os elementos que pertencem
   ao primeiro e ao segundo conjunto.

5. Verificar se um conjunto é SUBCONJUNTO de outro
   Esta operação recebe dois parâmetros, que são os dois conjuntos. 
   Ela deve retornar como resultado verdadeiro (o inteiro um) se todos os elementos do primeiro
   conjunto pertencerem também ao segundo conjunto ou falso (o inteiro zero), caso contrário.
   
Para testar as suas funções, escreva um script que lê dois arquivos, ambos contendo textos sem
pontuação. Durante a leitura, você deverá armazenar as palavras dos dois textos em dois conjuntos 
separados, de modo que o primeiro conjunto contenha todas as palavras do primeiro texto e o segundo
conjunto, as do segundo texto. Ao final, escreva na tela, uma por linha, as palavras que ocorrerem
nos dois textos.

Para facilitar, converta para maiúsculas as linhas dos dois arquivos durante a leitura.

Durante o processamento, manipule os conjuntos apenas através das cinco operações definidas acima.
Assim, se desejarmos futuramente mudar a representação, utilizando outro tipo no lugar de listas para
representar os conjuntos, o corpo principal do script não deverá precisar ser alterado.

Bom estudo! 

Oswaldo Vernet
