prologschememinikanren

How should I handle repeated updating in logical programming?


In particular I am trying to determine the best approach to solve the following type of problem:

The example I am interested in is the find-s algorithm in Mitchell's Machine Learning book were it is applied to 4 training examples.

The basic idea is for each training example, x, and hypothesis h, determine h' were it incorporates x by making it more general. I need to map h to h' for each x in the training set. The problem I am having is how to best approach this in a logical programming language. I am using minikanren which is roughly prolog embedded in scheme.

After computing each h', I need to then set! it to a global variable h, and then proceed to the next training example x. The code below is the main part of the program.

(define h '(0 0 0 0 0 0))

(define seto
  (lambda (x)
    (project (x)
             (lambda (s) (set! h x) (succeed s)))))

(run* (q)
     (fresh (x h0 h1)
            (trainingo x)
            (== h h0)
            (find-so h0 x h1)
            (seto h1)
            (== h1 q)))

h is the global variable, seto mutates h with h1 which is the next computed hypothesis from h0 and x training example using the find-s algorithm (find-so).

In prolog it would be (I think) equivalent to assert('hypothesis'(H)) after each training example X (overwriting the the previous one) and calling retract('hypothesis'(H)) after all the training examples have been applied.

Again my question is whether this is the best approach (via side-effects) for solving these kind of problems?

Edit: I accepted @mat answer in conjunction with his comment. In summary I needed to treat the training examples as a list and use forward recursion on that list until I got to the empty list. Were I was getting stuck was in having the training examples as part of the backtracking along with finding the next hypothesis instead of having them in a list of which I can recur on until empty.


Solution

  • What you suggest may seem tempting: Simulate global updates with assertz/0 and retract/1.

    However, there are major drawbacks if you do it this way:


    A declarative solution to simulate these state changes is to think in terms of relations between states.

    For example, when you use H0 to compute the next hypothesis H1, then you can express this as a relation between H0 and H1, and possibly further parameters. Think about predicates like:

    Note that such predicates can be read and—ideally—run in all directions!

    In total, the entire solution will in your case be modeled as a sequence of hypotheses:

    H0H1H2 → … → H

    For more information and pointers, see the closely related question:

    How to avoid using assert and retractall in Prolog to implement global (or state) variables