Unify.borg

Unify.borg


{
?f() :: f[3];

is_bool(a) ::
   tag(a) = 27; `previous version: tag = 6`

is_false(a) ::
   (tag(a) = 27) & !a;

`EQUAL-functie`
`vars zijn equal als hun naam dezelfde is`
`tabellen zijn equal als elk van hun elementen equal is`
`functies zijn equal als de naam dezelfde is en de paramlists even lang zijn`
`op al de rest wordt "=" opgeroepen`
equal(e1, e2) :: {
   iter(count, res) ::
      if ((count <= 0) | !res,
         res,
         iter(count - 1, equal(e1[count], e2[count])));
   if (!(tag(e1) = tag(e2)),
      false,
      if (is_ref(e1),
         e1 ~ e2, `origineel: e1[1] = e2[1]`
         if (is_table(e1) & (size(e1) = size(e2)),
            iter(size(e1), true),
            if (is_fun(e1), `vgl v 2 functies: namen + lengte v paramlist gelijk`
               `(e1[1] = e2[1]) & (size(e1[2]) = size(e2[2])),`
               e1 ~ e2,
               e1 = e2))))
};

deepcopy(list) ::
  if (is_table(list), {
        res[size(list)] : void;
        for (i : size(list), i > 0, i := i - 1, res[i] := deepcopy(list[i]));
        res
     },
     list);

assoclist() :: [0, []];

assocsize(list) :: list[1];

noassoc(f) ::
   `return value wanneer we een key opzoeken die niet in de lijst zit`
   if (is_fun(f),
      text(f[1]) = "noassoc",
      false);

findassoc(list, key) :: {
  iter(rest) :: {
    if (size(rest) = 0, noassoc,
      if (equal(rest[1], key), rest[2], iter(rest[3])))
  };
  iter(list[2])
};

addassoc(list, key, value) :: {
   if (noassoc(findassoc(list, key)), {
         list[1] := list[1] + 1;
         list[2] := [key, value, list[2]];
         true
      },
     false)
};

setassoc(list, key, value) :: {
   iter(rest) ::
     if (size(rest) = 0, void,
        if (equal(rest[1], key), rest, iter(rest[3])));
   tmp : iter(list[2]);
   if (is_voi(tmp), false, { tmp[2] := value; true })
};

makelist() :: [0, void];

addelement(list, el) :: {
   list[1] := list[1] + 1;
   list[2] := [el, list[2]];
   list
};

foreach(list, function) ::
   for (rest : list[2], !is_voi(rest), rest := rest[2], function(rest[1]));

append(list1, list2) :: {
   iter(rest) ::
      if (is_voi(rest[2]),
         rest[2] := deepcopy(list2[2]),
         iter(rest[2]));
   newlist : deepcopy(list1);
   if (newlist[1] = 0,
      newlist[2] := deepcopy(list2[2]),
      iter(newlist[2]));
   newlist[1] := newlist[1] + list2[1];
   newlist
};

unifyfailed(f) ::
   `return value wanneer unificatie mislukt`
   if (is_fun(f),
      text(f[1]) = "unifyfailed",
      false);

complete(tbl) ::
   `1e element van return value bij gelukte unificatie waarbij alle variabelen ingevuld zijn`
   `return value v unificatie is tabel v 3 elementen`
   `1e el: complete of incomplete`
   `2e el; - bij complete: de volledig geunifieerde expressie`
   `        - bij incomplete: lijst van expressies waarin nog variabelen zitten`
   `3e el: associatielijst van bindingen`
   is_table(tbl) & equal(tbl[1], complete);

incomplete(tbl) ::
   `1e element van return value bij gelukte unificatie waarbij nog niet alle variableen`
   `ingevuld zijn`
   is_table(tbl) & equal(tbl[1], incomplete);

checkexp(exp) :: {
   `kijkt of in tabel exp nog variabelen voorkomen`
   iter(i, result) ::
      if (!result,
         false,
         if (i <= 0,
            result,
            iter (i - 1, checkexp(exp[i]))));
   if (is_table(exp),
      iter (size(exp), true),
      !is_ref(exp))
};

basicunify(exp1, exp2, result) :: {
   changed : false;
   replace(list, exp, val, count) ::
      if (count > 0, {
            tmp : list[count];
            if (is_table(tmp),
               list[count] := replace(tmp, exp, val, size(tmp)),
               if (is_ref(tmp),
                  if (equal(tmp, exp),
                     list[count] := val)));
            replace(list, exp, val, count - 1)
         },
         list);
   assignvar(exp, val) :: {
      noloops(rest, count, res) ::
         if (!res,
            false,
            if (count <= 0,
               res,
               if (is_table(rest[count]),
                  noloops(rest, count - 1, noloops(rest[count], size(rest[count]), true)),
                  noloops(rest, count - 1, !equal(rest[count], exp)))));
      if (is_table(val) & !noloops(val, size(val), true),
         false, {
            if (is_table(exp1), replace(exp1, exp, val, size(exp1)), if (equal(exp1, exp), exp1 := val));
            if (is_table(exp2), replace(exp2, exp, val, size(exp2)), if (equal(exp2, exp), exp2 := val));
            changed := true;
            addassoc(result, exp, val)
         })
   };
   looptab(t1, t2, count, res) ::
      if (!res,
         false,
         if (count <= 0,
            res,
            looptab(t1, t2, count - 1, loop(t1[count], t2[count]))));
   loop(a, b) ::
      if (is_table(a),
         if (is_table(b),
            if (size(a) = size(b),
               looptab(a, b, size(a), true),
               false),
            if (is_ref(b),
               assignvar(b, a),
               false)),
         if (is_ref(a),
            if (is_ref(b),
               true,
               assignvar(a, b)),
            if (is_ref(b),
               assignvar(b, a),
               equal(a, b))));
   iter() :: {
      changed := false;
      if (loop(exp1, exp2),
         if (changed,
            iter(),
            if (checkexp(exp1) & checkexp(exp2),
               [complete, exp1, result],
               if (equal(exp1, exp2),
                  [incomplete, [1, [exp1, void]], result],
                  [incomplete, [2, [exp1, [exp2, void]]], result]))),
         unifyfailed)
   };
   iter()
};

union(a, b) :: {
   `berekend unie van 2 associatielijsten, return value = false wanneer lijsten niet`
   `compatibel zijn, dus wanneer een variabele in beide lijsten andere waarde heeft`
   iter (rest, result) ::
     if (size(rest) = 0,
        result,
        if (noassoc(val : findassoc(result, rest[1])),
           iter(rest[3], { addassoc(result, rest[1], rest[2]); result }),
           if (equal(val, rest[2]),
              iter(rest[3], result),
              false)));
   tmp : iter(a[2], assoclist());
   if (is_table(tmp),
      iter (b[2], tmp),
      false)
};

expandexp(exp, assoclist) :: {
   `loopt tabel exp af en zal voor iedere variabele in deze tabel proberen een waarde te zoeken`
   `uit de assoclist, wanneer waarde gevonden wordt, zal variabele in tabel vervangen worden door`
   `haar waarde, anders blijft var staan.  Return value = geexpandeerde tabel.`
   iter(i) ::
      if (i <= 0,
         exp, {
            exp[i] := expandexp(exp[i], assoclist);
            iter(i - 1)
         });
   if (is_table(exp),
      iter(size(exp)),
      if (is_ref(exp) & !noassoc(tmp : findassoc(assoclist, exp)),
         expandexp(tmp, assoclist), `origineel: tmp`
         exp))
};

cleanuplist(inc) :: {
   `incomplete structuur opkuisen: uit lijst van tabellen met nog in te vullen vars kijken welke`
   `van deze tabellen nu wel volledig ingevuld zijn, en deze verwijderen.`
   `als er nog maar 1 tabel overblijft die volledig ingevuld is, mag deze blijven staan, dit is`
   `de volledig geunifieerde expressie, het keyword 'incomplete' in de return value wordt dan`
   `vervangen door 'complete'.`
   iter (prev, rest) ::
      if (is_voi(rest),
         inc,
         if (!checkexp(rest[1]),
            iter(rest, rest[2]),
            if (list[1] = 1,
               [complete, rest[1], inc[3]], {
                  list[1] := list[1] - 1;
                  if (is_voi(prev),
                     list[2] := rest[2],
                     prev[2] := rest[2]);
                  iter(prev, rest[2])
               })));
   list : inc[2];
   if (list[1] = 0,
      list,
      iter(void, list[2]))
};

retrieve(key, result) ::
   `het opzoeken van de waarde van een variabele in een complete of incomplete ding`
   expandexp(key,result[3]);

unify(exp1, exp2) :: {
   `deepcopys zijn nodig vermits algoritme destructief werkt op beide expressies`
   exp1 : deepcopy(exp1);
   exp2 : deepcopy(exp2);
   simpleiter(rest, exp, result) ::
      `dient om een expressie te unifieren met een lijst van andere expressies: een voor een`
      `unifieren en nieuwe bindingen in result rammen`
      if (is_voi(rest),
         cleanuplist(result), {
            expandexp(rest[1], result[3]);
            tmp : basicunify(rest[1], exp, result[3]);
            if (unifyfailed(tmp),
               unifyfailed,
               if (complete(tmp),
                  simpleiter(rest[2], exp, [incomplete, addelement(result[2], tmp[2]), tmp[3]]),
                  simpleiter(rest[2], exp, [incomplete, append(result[2], tmp[2]), tmp[3]])))
         });
   distriter(rest, list, result) ::
      `wordt gebruikt wanneer we 2 incomplete dingen met elkaar unifieren`
      `vergelijkbaar met distributiefe vermenigvuldiging: telkens een elementje uit 1e incomplete`
      `ding unifieren met het 2e te unifieren incomplete ding (zit in var 'list')`
      if (is_voi(rest),
         cleanuplist(result), {
            expandexp(rest[1], result[3]);
            tmp : simpleiter(list, rest[1], [incomplete, makelist(), result[3]]);
            if (unifyfailed(tmp),
               unifyfailed,
               if (complete(tmp),
                  distriter(rest[2], list, [incomplete, addelement(result[2], tmp[2]), tmp[3]]),
                  distriter(rest[2], list, [incomplete, append(result[2], tmp[2]), tmp[3]])))
         });
   `nu volgt een hele hoop if-kes die gaan zien van welk type de expressies zijn die we meegegeven`
   `hebben aan de unify-oproep en aan de hand van deze types de nodige acties ondernemen.`
   if (unifyfailed(exp1) | unifyfailed(exp2),
      unifyfailed, `1 of 2 unifyfailed => unifyfailed`
      if (incomplete(exp1),
         if (incomplete(exp2),
            if (is_false(tmp : union(exp1[3], exp2[3])),
               unifyfailed,
               { t1 : exp1[2]; t2 : exp2[2]; distriter(t1[2], t2[2], [incomplete, makelist(), tmp])}), `both incomplete`
            if (complete(exp2),
               if (is_false(tmp : union(exp1[3], exp2[3])),
                  unifyfailed,
                  { t : exp2[2]; simpleiter (expandexp(t[2], tmp), expandexp(exp2[2], tmp), [incomplete, makelist(), tmp])}), `exp1 inc, exp2 complete`
               { t : exp1[2]; simpleiter(t[2], expandexp(exp2, exp1[3]), [incomplete, makelist(), exp1[3]]) })), `exp1 inc, exp2 list`
         if (complete(exp1),
            if (incomplete(exp2),
               if (is_false(tmp : union(exp1[3], exp2[3])),
                  unifyfailed,
                  { t : exp2[2]; simpleiter(t[2], exp1[2], [incomplete, makelist(), tmp]) }), `exp1 complete, exp2 incomplete`
               if (complete(exp2),
                     if (is_false(tmp : union(exp1[3], exp2[3])),
                        unifyfailed,
                        basicunify(expandexp(exp1[2], tmp), expandexp(exp2[2], tmp), [incomplete, makelist(), tmp])), `exp1 complete, exp2 complete`
                  basicunify(exp1[2], expandexp(exp2, exp1[3]), [incomplete, makelist(), exp1[3]]))), `exp1 complete, exp2 list`
            if (incomplete(exp2),
               { t : exp2[2]; simpleiter(t[2], exp1, [incomplete, makelist(), exp2[3]]) }, `exp1 list, exp2 incomplete`
               if (complete(exp2),
                  basicunify(expandexp(exp1, exp2[3]), exp2[2], exp2[3]), `exp1 list, exp2 complete`
                  basicunify(exp1, exp2, assoclist())))))) `both lists`
};


display("display(unify([?x,?y],[[1,?y],[2,?x]]))"+eoln);
display("display(unify([2,[1,?x]],[?x,[1,?x]]))"+eoln);
display("display(unify([1,2,?a],[1,?b,3]))"+eoln);
display("display(unify([1,2,3],?a))"+eoln);
display("display(unify(?a,[1,2,?a]))"+eoln);
display("display(unify([1,2,3],[?a,2,1]))"+eoln+eoln);

display("display(tmp:unify([1, 2, [4, ?a, ?b]], [?c, 2, ?d]))"+eoln);
display("display(unify([?a, ?b],[1,?a]))"+eoln);
display("display(unify([?a, [1, ?a]], [10, [1, 10]]))"+eoln);
display("display(unify([1,2,[4,?a,?b]],[?a,?b,?c]))"+eoln);
display("display(unify([?a, [?b, ?c]], [?b, [?c, ?b]]))"+eoln+eoln);

display("tmp : unify([1, 2, [4, ?a, ?b]], [?c, 2, ?d])"+eoln);
display("t : unify(tmp, [1,2,[4,?e,5]])"+eoln); ` = `
display("res : unify(t,[1,2,[4,6,5]])"+eoln); `werkt, probleem zat in laatste regel van addelement`

display("t1 : unify([?a,?b,?c,4],[?a,?b,3,?d])"+eoln);
display("t2 : unify([?a,2,?c,?d],[1,?b,?c,?d])"+eoln);
display("res : unify(t1,t2)"+eoln) ` =   argument type conflict    + `
}