>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.