Ficha OCaml : Tipos somaExercício : Digressões sobre árvores bináriasExercício : Fórmulas lógicas proposicionais Exercício : Calcular e derivar
Neste exercício vamos redescobrir uma estrutura de dados clássica, as árvores binárias, mas com um pequeno twist. Queremos guardar a altura de uma árvore no nodo raiz da árvore. Tal situação é relevante se o uso que temos das árvores nos obriga recorrentemente ao uso desta informação. Calcular a altura de uma árvore é custoso! Compensa assim trocar memoria por computação e arquivar esta informação na própria árvore. Uma preocupação que teremos ao manipular tais árvores é a gestão da altura. Quem trata do adequado arquivo? será razoável pedir este tratamento ao utilizador destas árvores?1 Não será melhor atribuir esta tarefa às funções da biblioteca que fornece esta estrutura de dados? Temos então aqui um campo de uma estrutura de dados que deve responder a uma propriedade (ser de facto a altura da árvore em causa, em qualquer momento da sua existência) e cuja manipulação convém ser ocultada ao utilizador da biblioteca.
Vamos também considerar que as árvores em questão possam ser árvores vazias. Veremos que esta escolha nos obriga a alguns cuidados quando pretendemos determinar a altura de uma árvore. Como representamos uma folha? Qual é a altura de uma árvore quando esta é vazia, ou então quando esta é uma folha?
'a abin
das árvores binárias eventualmente vazias com a informação da altura em cada nodo (por exemplo uma árvore de altura x
tem esta informação arquivada na raiz);empty : unit -> 'a abin
e node : a abin -> 'a -> 'a abin -> 'a abin'
tal que empty ()
crie uma árvore vazia e node esq x dir
crie uma árvore cuja raiz contém x
e que tenha por filho esquerdo a árvore esq
e por filho direito a árvore dir
, com a informação adequada para a altura arquivada no nodo raiz. Tais funções são designadas de smart constructors por construírem elementos de um tipo de dado tratando da logística própria do tipo para a qual não queremos o envolvimento do utilizador, aqui o arquivo correto da altura da árvore construída; height : 'a abin -> int
que calcula a altura de uma árvore; leaves : 'a abin -> int
que calcule o número de folhas de uma árvore;nodes : 'a abin -> int
que calcula o número total de nós de uma árvore, folhas incluídas;duplicate : 'a abin -> bool
que devolve true
se existe um elemento duplicado na árvore em parâmetro;sorted : ('a -> 'a -> int) -> 'a abin -> bool
tal que sorted comp ar
que devolve true
se a árvore ar
for uma árvore binária de pesquisa conforme o critério de comparação comp
. fold_dfs f init ar
que, a semelhança do fold_left
para as listas, aplica uma função binária f
a todos os elementos da árvore binária ar
usando a estratégia dfs (depth-first-search, em profundidade primeiro, da esquerda para a direita). O valor inicial do acumulador (que acumula o resultado da função f
no percurso dfs) é init
;map f ar
sobre as árvores binárias;fold_bfs f init ar
(breadth-first search, em largura primeiro, da esquerda para a direita) que aplica a função binária f
a todos os elementos da árvore ar
. O valor inicial do acumulador é init
;fold_dfs
.
O objetivo deste exercício é a exploração dos tipos soma. No caso deste exercício estamos interessado no tipo das expressões lógicas (proposicionais). Considere a fórmula proposicional seguinte:
Essa fórmula pode ser comodamente representada na forma de uma árvore (designada comumente de termo)
Define o tipo prop
das expressões lógicas proposicionais que envolvem variáveis proposicionais, os valores , , a negação , a implicação, a disjunção, a conjunção e a equivalência. Este tipo codifica uma fórmula proposicional como um termo.
Neste exercício assume-se que as variáveis proposicionais são de tipo string
;
define a função valor : (string*bool) list -> prop -> bool
que dado uma lista associativa das variáveis para os seus valores de verdade, devolve o valor de verdade da fórmula. Por exemplo, valor [("X",true); ("Y",false)] f = true
onde f
é a representação de tipo prop
da fórmula ;
define a função vars : prop -> string list
que devolve a lista das variáveis que ocorrem na fórmula em parâmetro. A lista resultante não deverá conter elementos duplicados;
define a função tabela_verdade : prop -> bool array array
que calcula a tabela de verdade da fórmula em parâmetro. Por exemplo tabela_verdade f
, em que f
é a representação de tipo prop
da fórmula , devolve a tabela :
que corresponde à tabela de verdade
Considere a expressão aritmética seguinte:
Podemos representar esta expressão pela árvore (termo) seguinte :
exp
das expressões aritméticas sobre inteiros e com variáveis (aqui codificadas com o tipo string
) envolvendo exclusivamente as operações básicas (soma, substração, produto, divisão);x
tem por valor 2 e y
vale 1, então a expressão dada em exemplo vale 22. Define assim a função calcula : (string * int) list -> expr -> int
que calcula o valor associado a uma expressão dada em parâmetro com base no valor das suas variáveis, também fornecido como parâmetro. Assim calcula [("x",2);("y",1)] e = 22
onde e
é a expressão aritmética dada no exemplo;deriva : expr -> string -> expr
que calcula a derivada de uma expressão numa variável. Assim deriva e x
devolve a expressão aritmética que é a derivada de e
na variável x
.