A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Jpf@fe.up.pt www.fe.up.pt/~jpf Métodos Formais em Engenharia de Software Especificação Baseada em Modelos em VDM++ (4ª parte) João Pascoal Faria jpf@fe.up.pt.

Apresentações semelhantes


Apresentação em tema: "Jpf@fe.up.pt www.fe.up.pt/~jpf Métodos Formais em Engenharia de Software Especificação Baseada em Modelos em VDM++ (4ª parte) João Pascoal Faria jpf@fe.up.pt."— Transcrição da apresentação:

1 jpf@fe.up.pt www.fe.up.pt/~jpf
Métodos Formais em Engenharia de Software Especificação Baseada em Modelos em VDM++ (4ª parte) João Pascoal Faria

2 Índice Expressões, padrões e ligações (bindings) Instruções
Funções avançadas Tipos básicos: O tipo “token” Tipos compostos: Tuplos e produtos cartesianos Constantes simbólicas Correspondência entre a notação matemática e a notação ASCII

3 Expressões, padrões e bindings
Expressão “let” Expressões condicionais “if” e “cases” Padrões Expressões quantificadas Ligações (bindings) Expressão de selecção “iota” Expressões de julgamento de tipos Expressões de julgamento de classes

4 Expressão “let” let definição1, definição2, … in expressão
Devolve valor da expressão da parte “in” usando definições de variáveis ou funções introduzidas na parte “let” Definição de variável (no sentido matemático): identificador = expressão Definição de variável (no sentido matemático) c/ padrão: padrão = expressão Definição de função: usando sintaxe habitual para definir função de forma explícita (assinatura introduzida antes dos nomes dos argumentos) Permite aumentar a legibilidade da especificação let identificador in set conjunto [be st condição] in expressão Escolhe um elemento arbitrário do conjunto para usar na expressão Devolve o valor da expressão da parte “in” No caso da parte “be st” existir (ler “be such that”), escolhe um elemento obedecendo à condição Outras formas: ver manual

5 Expressão “let” Exemplo: Função para obter o máximo dum conjunto de reais max(s: set of real) res: real == let x in set s in let resto = s \ {x} in if resto = {} then x else let max2: real * real -> real max2(a,b) == if a > b then a else b in max2(x, max(resto)) pre s <> {}; Escolhe valor arbitrário x de conjunto s para usar a seguir Define variável resto para usar a seguir Define função max2 para usar a seguir Escolhe valor de conjunto obedecendo a condição max(s: set of real) res: real == let x in set s be st not exists y in set s & y > x in x pre s <> {};

6 Expressões condicionais “if” e “cases”
if condição then expressão1 else expressão2 Se a condição for verdadeira, dá o valor da expressão1, senão dá o valor da expressão2 “elseif” = “else if” cases expressão: padrão11, padrão12, ..., padrão1N -> expressão1, > ..., padrãoM1, padrãoM2, ..., padrãoMN -> expressãoM, others -> expressãoM1 end Os padrões (ver tipos de padrões a seguir) são comparados por ordem com a expressão Se o 1º padrão a fazer “match” é padrãoij , devolve o valor de expressãoi Parte “others” é opcional Semelhante a “switch”, com a diferença de se poderem usar padrões

7 Expressões condicionais “if” e “cases”
Exemplo de utilização de “cases” com padrões Caso de sequência vazia (usa padrão de constante literal) mergesort : seq of nat -> seq of nat mergesort (s) == cases s: [] -> [], [x] -> [x], s1 ^ s2 -> merge (mergesort(s1), mergesort(s2)) end; merge : seq of nat * seq of nat -> seq of nat merge (s1, s2) == cases true: (s1 = []) -> s2, (s2 = []) -> s1, (hd s1 < hd s2) -> [hd s1] ^ merge(tl s1, s2), others -> [hd s2] ^ merge(s1, tl s2) end; Caso de sequência com um único elemento x (usa padrão de enumeração de sequência e padrão de identificador) Caso de sequência que se pode exprimir como a concatenação de duas subsequências não vazias (usa padrão de concatenação de sequências e padrão de identificador) Usa padrão “valor de expressão”. Necessita parêntesis!

8 Padrões identifier literal - (expression) {p1, p2, …} p1 union p2
Tipo de padrão Descrição identifier Faz match com qualquer valor, fixando o valor do identificador. literal Constante literal. Só faz match com o mesmo valor. - Don’t care. (expression) Valor de uma expressão. Só faz match com o mesmo valor. Parêntesis podem ser necessários para não confundir com outros padrões. {p1, p2, …} Faz match com um conjunto com o mesmo nº de elementos, e que fazem match com os padrões p1, p2, etc. (por qualquer ordem). p1 union p2 Faz match com um conjunto que se pode exprimir como a união de dois subconjuntos disjuntos não vazios que fazem match com os padrões p1 e p2. [p1, p2, …] Faz match com uma sequência com o mesmo nº de elementos, e que fazem match com os padrões p1, p2, etc. (pela mesma ordem). p1 ^ p2 Faz match com uma sequência que se pode exprimir como a concatenação de duas subsequências não vazias que fazem match com os padrões p1 e p2. mk_(p1, p2, …) Faz match com um tuplo com o mesmo nº de componentes, e que fazem match com os padrões indicados (pela mesma ordem). mk_RecordName( p1, p2, …) Faz match com um record do mesmo tipo e com o mesmo nº de componentes, e que fazem match com os padrões indicados (pela mesma ordem).

9 Expressões quantificadas
forall binding & condição exists binding & condição exists1 binding & condição “qualquer que seja … verifica que …” “existe pelo menos um … tal que …” 1 “existe um e um só … tal que …”

10 Ligações (bindings) Set binding: padrão1, ..., padrãoN in set conjunto
Tenta fazer match dos padrões com os elementos do conjunto, fixando (binding) os valores dos identificadores introduzidos nos padrões Na maioria dos casos, os padrões são simplesmente identificadores Type binging: padrão1, ..., padrãoN : tipo Semelhante ao anterior, só que considera as instâncias de um tipo (potencialmente em nº infinito!) em vez dos elementos de um conjunto Type bindings não são executados pelo interpretador! Usados principalmente em quantificadores e compreensões

11 Expressões quantificadas
Exemplo: restrição de unicidade de chave -- número é chave de sócio, isto é, não podem existir -- dois sócios diferentes com o mesmo número inv not exists s1, s2 in set sócios & s1 <> s2 and s1.GetNúmero() = s2.GetNúmero(); -- número é chave de sócio, isto é, não podem existir -- dois sócios diferentes com o mesmo número inv not exists s1, s2 in set sócios & s1 <> s2 and s1.GetNúmero() = s2.GetNúmero(); ou, equivalentemente (pelas leis de De Morgan): inv forall s1, s2 in set sócios & s1 <> s2 => s1.GetNúmero() <> s2.GetNúmero();

12 Expressão de selecção “iota”
iota identificador in set conjunto & condição Selecciona o único elemento do conjunto que obedece à condição Outras formas da expressão “iota”: ver manual Exemplo: Operação que selecciona o sócio com um determinado número (chave) Exemplo do máximo public GetSócio(número: nat1) res: Sócio == return iota s in set sócios & s.GetNúmero() = número pre exists1 s in set sócios & s.GetNúmero() = número; max(s: set of real) res: real == iota x in set s & (not exists y in set s & y > x) pre s <> {};

13 Expressões de julgamento de tipos
Sintaxe Semântica Exemplos is_typeName( expression) Verifica se a expressão é do tipo indicado. Só é aplicável a tipos básicos e records. is_bool(1)  false is_Date(mk_Date(2001,1,1))  true is_(expression, typeExpr) Verifica se a expressão é do tipo indicado. É aplicável também a outros tipos. size: set of nat | seq of nat -> nat size(s) == if is_(s, seq of char) then len s else card s; Útil sobretudo quando se usam uniões!

14 Expressões de julgamento de classes
Sintaxe Semântica isofclass(className, object_ref) Verifica se o objecto indicado é uma instância da classe indicada ou de uma subclasse sameclass(object_ref1, object_ref2) Verifica se os dois objectos são instâncias da mesma classe isofbaseclass(className, object_ref) Verifica se o objecto indicado é instância duma classe que tem a classe indicada como raiz na hierarquia de classes samebaseclass(object_ref1, object_ref2) Verifica se os dois objectos são instâncias de classes que têm uma classe comum como raiz na hierarquia de classes Útil sobretudo quando se usam subclasses (equivalente OO a uniões)!

15 Expressões de julgamento de classes
Considerando Oi instância de Ci, em relação a O2 são verdadeiras (apenas) as seguintes expressões: isofclass(C2,O2) isofclass(C1,O2) isofclass(C5,O2) isofbaseclass(C1,O2) isofbaseclass(C5,O2) sameclass(O2,O2) samebaseclass(O1,O2) samebaseclass(O2,O2) samebaseclass(O3,O2) samebaseclass(O4,O2) samebaseclass(O5,O2)

16 Instruções Atribuição Blocos Declaração de variáveis
Instruções “let” e “def” Instruções condicionais “if” e “cases” Ciclos “for” e “while” Instrução “return”

17 Atribuição designador_de_estado := expressão Nome de variável
Variável de instância do objecto em causa Variável estática (static) Variável local da operação (declarada com dcl) Parte de variável do tipo map, seq ou record map_var(chave) := valor seq_var(índice) := valor record_var.campo := valor Não se pode fazer object_reference.instance_variable := expr (mesmo que a variável de instância seja pública)! Um identificador introduzido com let , forall, etc. não é uma variável neste sentido

18 Atribuição múltipla atomic ( sd1 := exp1; sd2 := exp2; …)
Avalia primeiro todas as expressões do lado direito, e só depois atribui (em simultâneo) os valores resultantes às variáveis do lado esquerdo! Só verifica invariantes no final das várias atribuições (senão, verifica invariantes após cada atribuição) Útil na presença de invariantes que envolvem mais do uma variável de instância (do mesmo objecto) Não resolve o problema de invariantes inter-objecto, isto é, que envolvem múltiplos objectos (porquê?)

19 Atribuição múltipla instance variables
private quantidade : real; private precoUnitario : real; private precoTotal : real; inv precoTotal = quantidade * precoUnitario; operations public SetQuantidade(q: real) == (quantidade := q; precoTotal := precoUnitario * q); Quebra invariante após 1ª atribuição public SetQuantidade(q: real) == atomic(quantidade := q; precoTotal := precoUnitario * q); public SetQuantidade(q: real) == atomic(quantidade:=q; precoTotal:=precoUnitario * quantidade); Errado: usa valor antigo da variável

20 Blocos e declaração de variáveis
( dcl id1 : tipo1 [:= expr1], id2 : tipo2 [:= expr2], …; dcl … ; … instrução1; instrução2; … ) Um bloco tem de ter pelo menos uma instrução Variáveis só podem ser declaradas no início do bloco Última instrução não precisa de “;” A 1ª instrução que retornar um valor (mesmo sem “return”, basta chamar uma operação que devolva um valor) faz terminar o bloco

21 Instruções “let” e “def”
let definição1, definição2, … in instrução let identificador in set conjunto [be st condição] in instrução def definição1, definição2, … in instrução Têm a mesma forma que expressões “let” e “def”, com instrução em vez de expressão na parte de “in” Usar “def” em vez de “let”, quando na parte de definições são invocadas operações que alteram estado Identificadores introduzidos na parte de definições não são variáveis, i,e. não podem aparecer do lado esquerdo de atribuições!

22 Instruções condicionais “if” e “cases”
if condição then instrução1 [else instrução2] cases expressão: padrão11, padrão12, ..., padrão1N -> instrução1, > ..., padrãoM1, padrãoM2, ..., padrãoMN -> instruçãoM, others -> instruçãoM1 end Têm a mesma forma que as expressões “if” e “cases”, com instruções em vez de expressões Na instrução “if”, a parte de “else” é opcional

23 Ciclos “for” e “while” while condição do instrução
Descrição while condição do instrução Ciclo “while” tradicional for contador = N1 to N2 [by N3] do instrução Ciclo “for” tradicional, com inteiros. Contador não tem de ser declarado previamente. for all padrão in set conjunto do instrução Normalmente o padrão é simplesmente um identificador. Percorre os elementos do conjunto por uma ordem arbitrária. Não confundir com quantificador existencial “forall”. for padrão in sequência do instrução Normalmente o padrão é simplesmente um identificador. Percorre os elementos da sequência por ordem.

24 Instrução “return” return return expressão
Usado para terminar operações que não retornam qualquer valor return expressão Usado para terminar operações que retornam um valor

25 Funções avançadas Funções polimórficas Funções de ordem superior
O tipo função A expressão lambda Exemplo combinado

26 Funções polimórficas nomeFunção[@TypeParam1, @TypeParam2, …] …
São funções genéricas, que podem ser usadas com valores de diferentes tipos Têm parâmetros especiais (type parameters) que devem ser substituídos por nomes de tipos concretos ao usar a função Nomes desses parâmetros começam por e são indicados entre parêntesis rectos a seguir ao nome da função Semelhantes a function templates em C++

27 Funções polimórficas Exemplo: função utilitária, que verifica se uma sequência de elementos de um tipo qualquer tem duplicados: Exemplo de utilização dessa função: public static seq res: bool == exists i, j in set inds s & i <> j and s(i) = s(j); class Publicação instance variables private autores: seq of Autor := []; inv not HasDuplicates[Autor](autores); Passa um tipo concreto

28 Funções de ordem superior
São funções que recebem outras funções como argumentos, ou (Curried functions) que retornam funções como resultado I.e. têm argumentos ou resultado do tipo função Exemplo: função que acha um zero aproximado duma função entre limites especificados, com erro máximo especificado, pelo método das bissecções sucessivas: findZero( f: real -> real , x1, x2, err: real) res: real == if abs(x1 - x2) <= err and abs(f(x1) – f(x2)) <= err then x1 else let m = (x1 + x2) / in if sinal(f(m)) = sinal(f(x1)) then findZero(m,x2) else findZero(x1,m) pre sinal(f(x1)) <> sinal(f(x2));

29 O tipo função Função total: arg1Type * arg2Type * … +> resultType
Função parcial: arg1Type * arg2Type * … -> resultType O tipo de uma função é definido pelos tipos de argumentos e resultado Instâncias de um tipo de função (i.e. funções concretas) podem ser passadas como argumento ou retorno de funções, e guardadas (por referência) em estruturas de dados Pode-se ver como um único argumento do tipo tuplo (instância do produto cartesiano)

30 O tipo função

31 A expressão lambda lambda padrãoArg1: Tipo1, …, padrãoArgN: TipoN & expr Constrói uma função on the fly Padrões normalmente são simplesmente identificadores de argumentos Usado normalmente para passar como argumento a outra função (de ordem superior) Exemplo: achar um zero real de um polinómio findZero(lambda x: real & 5 * x**3 - x**2 - 2 , 0, 1, )

32 Exemplo de funções polimórficas, funções de ordem superior e expressões lambda
class Biblioteca instance variables private sócios: set of Sócio; private publicações: set of Publicação; operations public GetPublicaçõesMaisEmprestadas() res : seq of Publicação == return SeqUtils`SortBy[Publicação](publicações, lambda p: Publicação & len p.GetEmpréstimos(), <Desc>); public GetSóciosComMaisEmpréstimos() res : seq of Sócio == return SeqUtils`SortBy[Sócio](sócios, lambda s: Sócio & card s.GetEmpréstimos(), <Desc>); end Biblioteca

33 Exemplo de funções polimórficas, funções de ordem superior e expressões lambda
class SeqUtils functions -- Ordena uma sequência com base numa função de comparação. -- compare(a,b) deve dar >0 =0 ou <0 conforme a>b, a=b ou a<b. public static seq -> int) res: seq == if s = [] then [] else s, s, compare), compare); -- Função auxiliar que insere um valor numa sequência ordenada. private s: seq -> int) res : seq == cases true : (s = []) -> [i], (compare(i, hd s) <= 0) -> [i] ^ s, others -> [hd s] ^ tl s, compare) end; ...

34 Exemplo de funções polimórficas, funções de ordem superior e expressões lambda
types public SortDirection = <Asc> | <Desc>; functions -- Ordena um conjunto por ordem ascendente ou descendente, -- com base no valor de uma função que é aplicada a cada elemento. public static set -> int, dir : SortDirection) res: seq == lambda & if dir = <Asc> then func(e1)-func(e2) else func(e2)-func(e1)); -- Função auxiliar que converte um conjunto para uma sequência arbitrária private static set res: seq == if arg = {} then [] else let elem in set arg in [elem] ^ \ {elem}); end SeqUtils

35 O tipo token Tipo muito primitivo, que apenas suporta comparações de igualdade e desigualdade Usado normalmente em fases iniciais da especificação, quando se sabe pouco sobre um determinado tipo

36 O tipo token Exemplo: no colocação de professores, há entradas e saídas do tipo Vaga e Professor, mas não é relevante o seu conteúdo, apenas é necessário poder comparar com “=” e “<>” Para efeitos de teste, pode-se definir types Professor = token; Vaga = token; No código de teste, pode-se instanciar como se quiser (por exemplo, com inteiros): dcl p1 : Professor := mk_token(1); dcl p2 : Professor := mk_token(2); dcl v1 : Vaga := mk_token(1); dcl v2 : Vaga := mk_token(1);

37 Tuplos e produtos cartesianos
Um tuplo é uma instância de um produto cartesiano de tipos Distingue-se de um record porque os componentes são anónimos (podem ser acedidos por posição apenas) Exemplo: types Matriz = map nat1 * nat1 to real; functions criaMatriz(numLinhas, numColunas: nat1) : Matriz == { mk_(i, j) |-> 0.0 | i in set {1, ..., numLinhas}, j in set {1, ..., numColunas} }; produto cartesiano de tipos Sendo A uma matriz, A(mk_(i,j)) dá valor na linha i e coluna j construção de tuplo

38 Tuplos e produtos cartesianos

39 Constantes simbólicas
Constantes simbólicas são constantes às quais é dado um nome, por forma a tornar a especificação mais legível e fácil de alterar São declaradas na secção “values” com “nome = valor” ou “nome : tipo = valor” Exemplo: class DateUtils values public MinDate = mk_Date(1,1,1); …

40 Correspondência entre a notação matemática e a notação ASCII


Carregar ppt "Jpf@fe.up.pt www.fe.up.pt/~jpf Métodos Formais em Engenharia de Software Especificação Baseada em Modelos em VDM++ (4ª parte) João Pascoal Faria jpf@fe.up.pt."

Apresentações semelhantes


Anúncios Google