[m-users.] Inferring over dynamic data

Zoltan Somogyi zoltan.somogyi at runbox.com
Tue Jan 18 20:07:56 AEDT 2022


2022-01-18 18:01 GMT+11:00 "Stepp, Nigel D" <ndstepp at hrl.com>:
> Yes, this is exactly the kind of thing I'm interested in. What I don't get, though, is how you can use backtracking and forward inference chaining, etc on the data structure as if it were a collection of facts. When I think about doing that, it seems as though I am reimplementing part of the core language.
> 
> 
> If anyone has pointers to an example of this kind of method, I would be very appreciative.​

I already gave an example piece of Mercury code for computing the intersection of factA and factB.

> Is it the case that every predicate that would otherwise rely on the database of facts, should instead have a preamble that extracts and attempts unification with some part of the data structure?

Calling a predicate in Prolog *is* code that "attempts unification with some parts of a data structure".

> p(Facts,A,B) :-
> 
>     memberchk(factA(A),Facts),
> 
>     memberchk(factB(B),Facts),
> 
>     ...

No, that is not what I meant at all. What I meant was code like the example I gave
in my earlier email, and the example below.

> I feel like what I want is something like a monadic state a la Haskell where the database used for solving is provided that way.

Consider an example that in Prolog would use two dynamic predicates:

- s/1, which represents a set of items called i1, i2, i3 etc, and
- m/2, which maps each item to a list of items (i.e. its first argument is an item, and
  its second argument is a set of items). It could map each widget to its components.

example:

s(i1). s(i3).
m(i1, [i2, u3]). m(i2, []), m(i3, [i4, i5]).

Example Prolog predicate that operates on these two predicates:

add_new_component(Item, NewComponent) :-
   m(Item, OldComponents),
  retract(m(Item, OldComponents),
  NewComponents = [NewComponent | OldComponents], 
  assert(m(Item, NewComponents)),
  assert(s(Item)).

In Mercury, the direct equivalent of this code is

add_new_component(Item, NewComponent, S0, S, M0, M) :-
  map.lookup(Item, OldComponents),
  NewComponents = [NewComponent | OldComponents],
  map.det_update(Item, NewComponents, M0, M),
  set.insert(Item, S0, S).

Using state variable notation, which is described in section 3 of the Prolog
to Mercury transition guide, you could replace both "S0, S" pairs with !S,
and both "M0, M" pairs with !M. This is as close as Mercury gets to monadic state.
The main difference is that once people have state variables described to them,
they understand it, and don't have to read a "what are monads" paper as
a refresher every few months :-)

So you see: despite the fact that you have to carry along the state
of the data structures you are updating as explicit arguments, usually
as an argument pair (with the first element of the pair representing
the state before an operation, and the second giving the state after),
but sometimes as just a single argument (in situations in which
an operation looks at some state but does not update it),
this code is not really any more complex that the Prolog version.
In fact, it is shorter, because map.det_update does the job
of both retract and assert. And the readers of add_new_component
know, just from reading its declaration, that this predicate does not touch
any data structures other than s and m (since only s and m appear
in its argument list), and they also know that add_new_component
updates both s and m (because both have an in,out argument pair).
They know that s is a set, and the m is a map (from their types),
and that the elements types must match.

If that is not enough, don't make us guess what *would* be enough; give us a small example
in Prolog of the kind of thing you would like to do.

 Zoltan.


More information about the users mailing list