Search code examples
algorithmloopsclipsexpert-system

Sorting algorithm of multifield variable in CLIPS


I jsut started to learn CLIPS and I made a simple sorting algorithm to sort multifield variables in ascending order, the problem is that the return multifield variable isn't modified during the algorithm

    (deffunction sort (?multifield)
        (bind ?size (length$ ?multifield))
        (loop-for-count (?i 1 (- ?size 1))
            (loop-for-count (?j (+ ?i 1) ?size)
                (printout t (nth$ ?i ?multifield) " " (nth$ ?j ?multifield) crlf)
                (if (> (nth$ ?i ?multifield) (nth$ ?j ?multifield)) then
                    (printout t "> " (nth$ ?i ?multifield) " " (nth$ ?j ?multifield) crlf)
                    (bind ?temp (nth$ ?i ?multifield))
                    (replace$ ?multifield ?i ?i (nth$ ?j ?multifield))
                    (replace$ ?multifield ?j ?j ?temp)
                    (printout t "> que" (nth$ ?i ?multifield) " " (nth$ ?j ?multifield) crlf)
                )
            )
        )
        (return ?multifield)
)

This is a simple case where you can see the printed conditions and a correct execution of the algorithm but an incorrect return value:

CLIPS>  (sort (create$ 3 6 4 1))
3 6
3 4
3 1
before replacement multifield(i) and multifield(j) 3 1
after replacement multifield(i) and multifield(j) 3 1
6 4
before replacement multifield(i) and multifield(j) 6 4
after replacement multifield(i) and multifield(j) 6 4
6 1
before replacement multifield(i) and multifield(j) 6 1
after replacement multifield(i) and multifield(j) 6 1
4 1
before replacement multifield(i) and multifield(j) 4 1
after replacement multifield(i) and multifield(j) 4 1
(3 6 4 1)

Solution

  • Citing from the docs

    The replace$ function replaces a range of field in a multifield value with a series of single-field and/or multifield values and returns a new multifield value containing the replacement values within the original multifield value.

    So, replace$ does not modify the multifield passed in, but returns a new mutifield with the replaced values, which you have to bind again ...

    (deffunction mysort (?multifield)
        (bind ?size (length$ ?multifield))
        (loop-for-count (?i 1 (- ?size 1))
            (loop-for-count (?j (+ ?i 1) ?size)
                (printout t (nth$ ?i ?multifield) " " (nth$ ?j ?multifield) crlf)
                (if (> (nth$ ?i ?multifield) (nth$ ?j ?multifield)) then
                    (printout t "> " (nth$ ?i ?multifield) " " (nth$ ?j ?multifield) crlf)
                    (bind ?temp (nth$ ?i ?multifield))
    
                    (bind ?multifield (replace$ ?multifield ?i ?i (nth$ ?j ?multifield)))
                    (bind ?multifield (replace$ ?multifield ?j ?j ?temp))
    
                    ; or you can do the two above replacements in one call
                    ; (bind ?multifield (replace$ (replace$ ?multifield ?i ?i (nth$ ?j ?multifield)) ?j ?j ?temp)) 
    
                    (printout t "> que" (nth$ ?i ?multifield) " " (nth$ ?j ?multifield) crlf)
                )
            )
        )
        (return ?multifield)
    )