>From time to time, I test Racklog, in the hope that the Racket team 
replaced it with something more efficient. After all, there are many good 
implementations of Prolog like languages around. I simply cannot understand 
why Racket must be packed with a ridiculously slow piece of software, such 
as Racklog. Therefore, in order to discover how difficult would be the 
implementation of an efficient version of Racklog, I decided to check what 
I could do in Common Lisp. The reason for choosing Common Lisp is that 
there are a few inference machines in Lisp, so I did not need to start from 
scratch.

I found a book by Patrice Boizumalt that explained how to implement  
Prolog; the examples are in Common Lisp. I also found the material 
published in Japanese by Daiki Matsunaga from the Kioto Institute of 
Technology. The implementations of Boizumalt and Matsunaga are incomplete. 
For instance, they did not implement floating point. It took me about one 
hour to complete their implementations. Besides this, both implementations 
had bugs, which I fixed, and raised an issue on the github pages of the 
authors. Finally, I tested the programs with small grammars, puzzles and 
loops, just to check the tail call optimization. Here is the comparison 
between Matsunaga's Prolog and cxprolog:

```
%% File: again.pl
› cat again.pl

loop(0, Acc, Acc) :- !.
loop(N, Acc, F) :- A1 is Acc + 0.1, N1 is N - 1, loop(N1, A1, F).
```

Here is the execution in cxprolog:

```
~/wrkLisp/wam
› ./cxp
CxProlog version 0.98.2 [development]

[main] ?- consult('again.pl').
% File 'again.pl' consulted, 0.000106 sec 2768 bytes
yes

[main] ?- X1 is cputime, loop(2000000, 0.1, F), T is cputime - X1.
X1 = 0.050186
F = 200000.1
T = 133.843561
```

So, cxprolog executed 2 millions of repetitions in about 130 seconds. By 
the way, cxprolog is written in c. Now, here is the execution of 
Matsunaga's Prolog, which is written in Lisp:

```
~/wrkLisp/wam› rlwrap ros run
* (load "wam.lisp")
T
* (repl)
* (repl)
> ?- consult('again.pl').

yes.
> ?- cputime(X1), loop(2000000, 0.1, F), cputime(X2), T is X2 - X1.
F = 197024.88
X1 = 3804
X2 = 11729
T = 7925

yes.
> ?- cputime(X1), loop(2000000, 0.1, F), cputime(X2), T is X2 - X1.
F = 197024.88
X1 = 11730
X2 = 19832
T = 8102

yes.
> ?- cputime(X1), loop(2000000, 0.1, F), cputime(X2), T is X2 - X1.
F = 197024.88
X1 = 19833
X2 = 28478
T = 8645

yes.
```

I added floating point and the predicate cputime(X) to Matsunaga's code, 
and corrected a few bugs. The modified program is about 16 times faster 
than cxprolog. Matsunaga wrote an interpreter, in order to execute code for 
the Warren Abstract Machine. Of course, the is very inefficient. Therefore, 
I expanded each instruction that appear in the code into Lisp programs. 
Consider the code below, that Matsunaga's interpreter executes. I created a 
Lisp definition for the loop predicate, where I expanded each definition, 
according to what appears in the interpreter. Thus, the Lisp code became 
considerably faster than the cxprolog code.  I did this in about one day. 
Here is my question: Since it is so easy to write an efficient Prolog in 
Lisp, why the Racket community insists in using Racklog? I would like to 
propose a project to implement an efficient version of Racklog, based in 
Matsunaga's version of the Warren Abstract Machine. The first step is to 
fix all bugs that still remain in the Lisp version, and expand the 
instructions to eliminate the necessity of the interpreter. After obtaining 
a flawless Lisp version, one can prepare a Scheme/Racket version.

```
* (gethash (cons '|loop| 3) *dispatching-code-table*)
((TRY-ME-ELSE #:G525
  ((TRUST-ME) (ALLOCATE) (GET-VARIABLE-PERMANENT 4 1)
   (GET-VARIABLE-PERMANENT 3 3) (PUT-VARIABLE-PERMANENT 2 1)
   (PUT-CONSTANT 0.1 3) (CALL (|plus| . 3) 4) (PUT-VARIABLE-PERMANENT 1 1 4)
   (PUT-UNSAFE-VALUE 4 2) (PUT-CONSTANT 1 3) (CALL (|minus| . 3) 3)
   (PUT-UNSAFE-VALUE 1 1 3) (PUT-UNSAFE-VALUE 2 2) (PUT-UNSAFE-VALUE 3 3)
   (DEALLOCATE) (EXECUTE (|loop| . 3))))
 (GET-CONSTANT 0 1) (GET-VALUE-TEMPORARY 2 3) (NECK-CUT) (PROCEED)
 (LABEL #:G525) (TRUST-ME) (ALLOCATE) (GET-VARIABLE-PERMANENT 4 1)
 (GET-VARIABLE-PERMANENT 3 3) (PUT-VARIABLE-PERMANENT 2 1) (PUT-CONSTANT 
0.1 3)
 (CALL (|plus| . 3) 4) (PUT-VARIABLE-PERMANENT 1 1 4) (PUT-UNSAFE-VALUE 4 2)
 (PUT-CONSTANT 1 3) (CALL (|minus| . 3) 3) (PUT-UNSAFE-VALUE 1 1 3)
 (PUT-UNSAFE-VALUE 2 2) (PUT-UNSAFE-VALUE 3 3) (DEALLOCATE)
 (EXECUTE (|loop| . 3)))

* (show-wamcode "loop" 3)
          try-me-else G525
          get-constant 0,A1
          get-value X2,A3
          neck-cut
          proceed
G525:     trust-me
          allocate
          get-variable Y4,A1
          get-variable Y3,A3
          put-variable Y2,A1
          put-constant 0.1,A3
          call plus/3,4
          put-variable Y1,A1
          put-unsafe-value Y4,A2
          put-constant 1,A3
          call minus/3,3
          put-unsafe-value Y1,A1
          put-unsafe-value Y2,A2
          put-unsafe-value Y3,A3
          deallocate
          execute loop/3
NIL
```




-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/4667bdbf-b466-439f-b71e-2c836ee3d2c0%40googlegroups.com.

Reply via email to