

El algoritmo de unificación recibe dos referencias $m y $n a los
árboles que van a ser unificados. Retorna verdadero si la unificación puede
tener lugar y falso en caso contrario.
La equivalencia se mantiene utilizando un atributo cuyo nombre es $set.
Todos los nodos en una clase de equivalencia tienen un único representante.
Los atributos $set de los nodos
en una misma clase referencian al representante
(posiblemente de forma indirecta, via los campos $set de otros nodos).
El atributo $set del representante canónico apunta a si mismo.
Inicialmente cada nodo esta en una clase única.
99 sub unify {
100 my ($m, $n) = @_;
101
102 my $s = representative($m);
103 my $t = representative($n);
104
105 return 1 if ($s == $t);
106
107 return 1 if $samebasic->($s, $t);
108
109 print "Unifying ".representative($s)->str." and ".representative($t)->str."\n" if $debug;
110 return 1 if (mergevar($s, $t));
111
112 if (ref($s) eq ref($t)) {
113 $s->{$set} = representative($t);
114 my $i = 0;
115 for ($s->children) {
116 my $tc = $t->child($i++);
117 return 0 unless unify($_, $tc);
118 }
119 return 1;
120 }
121
122 return 0;
123 }
Nótese que unificar $m y $n es unificar sus representantes canónicos
$s y $t. Los representantes serán iguales si $m y $n
ya están en la misma clase de equivalencia.
El algoritmo de unificación usa las siguientes funciones auxiliares:
representative retorna una referencia al representante ccanónico
de la clase:
83 sub representative {
84 my $t = shift;
85
86 if (@_) {
87 $t->{$set} = shift;
88 return $t;
89 }
90 $t = $t->{$set} while defined($t->{set}) && ($t != $t->{$set});
91 die "Representative ($set) not defined!".Dumper($t) unless defined($t->{set});
92 return $t;
93 }
También permite cambiar el representante.
$s y $t representan el mismo tipo básico la función
referenciada por $samebasic devolverá verdadero. La función
$samebasic es definida por medio de la función set
junto con los otros parámetros del algoritmode unificación.
203 Aho::Unify->set(
204 key => 'set',
205 isvar => sub { $_[0] =~ /^Parse::Eyapp::Node::TYPEVAR/ },
206 samebasic => sub {
207 my ($s, $t) = @_;
208
209 return (((ref($s) eq 'INT') || (ref($s) eq'STRING')) && (ref($s) eq ref($t)));
210 },
211 debug => $debug,
212 );
$s o $t es una variable la introducimos en la clase de
equivalencia de la otra. Puesto que cada variable fresca es un único nodo (estamos trabajando con un DAG)
la actualización de la clase de equivalencia será visible en todas las apariciones de esta variable.
Además representative recorre la lista de enlaces de unificación retornando
el tipo básico o constructor con el que la variable se ha unificado.
La función mergevar mezcla las clases de equivalencia cuando uno de los
representantes es una variable:
67 sub mergevar {
68 my ($s, $t) = @_;
69
70 if (isvar($s)) {
71 $s->{$set} = representative($t);
72 print $s->str." = ".representative($t)->str."\n" if $debug;
73 return 1;
74 }
75 if (isvar($t)) {
76 $t->{$set} = representative($s);
77 print $t->str." = ".representative($s)->str."\n" if $debug;
78 return 1;
79 }
80 return 0;
81 }
set
una función $isvar que permite añadir variables adicionales:
23 sub isvar {
24 my $x = $isvar->(@_);
25 return $x if $x;
26 return 1 if $_[0] =~ /^Parse::Eyapp::Node::TYPEVAR::[\w:]+$/;
27 }
El espacio de nombres Parse::Eyapp::Node::TYPEVAR
se usa para las variables.
pl@nereida:~/doc/casiano/PLBOOK/PLBOOK/code/Aho-Polymorphism/lib/Aho$ cat -n Unify.pm
1 package Aho::Unify;
2 use Data::Dumper;
3 use Parse::Eyapp::Node;
4 use base qw (Exporter);
5 our @EXPORT_OK = qw(
6 unify
7 new_var
8 fresh
9 representative
10 strunifiedtree
11 hnewunifiedtree
12 newunifiedtree
13 selfrep
14 );
15 our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );
16
17 my $count = 0;
18 my $set = 'representative';
19 my $isvar = sub { };
20 my $samebasic = sub { };
21 my $debug = 0;
29 sub set {
30 my $class = shift if @_ %2;
31 $class = __PACKAGE__ unless defined($class);
32
33 my %handler = @_;
34
35 $set = 'representative';
36 $set = $handler{key} if exists($handler{key});
37 $isvar = $handler{isvar} if exists($handler{isvar});
38 $samebasic = $handler{samebasic} if exists($handler{samebasic});
39 $debug = $handler{debug} if exists($handler{debug});
40 $count = 0;
41
42 bless { key => $set, isvar => $isvar, samebasic => $samebasic, count => $count }, $class;
43 }

