Your profile icon looks like the same as the family emblem of Tokugawa,which governed
Edo age of Japan (1603-1867 ?). The emblem is still alive, and popular to seen in Samurai movies in Japan. I am not familiar at all with use of such emblems of royal family as profile icon. But I feel it is too private for one to use for that purpose, unless at least one is a descendant of the family. Sorry for this noisy comment.
It is not noisy comment, thank you for your voice in this topic. I will change it to my current photo.
Done another way. Emblem was used by me to indicate both kendo I practise and JPN approach to coding in general. As a way, I would say.
l am not sure that I understood fully discussions done in this thread. What I learned is that top level bare variable X for callable term is always wrapped with call(X) by the reader, and therefore test/2 below must not be expected to work as test2/2. I have to be careful for not confusing the two because so far I thought both were equal to each other for X=(!).
test(1, X):- X.
test(2,_).
test(3,_).
% ?- test(A, !).
%@ A = 1 ;
%@ A = 2 ;
%@ A = 3.
test2(1, X):- (X = (!) -> !; call(X) ).
test2(2,_).
test2(3,_).
% ?- test2(A, !).
%@ A = 1.
% ?- test2(A, true).
%@ A = 1 ;
%@ A = 2 ;
%@ A = 3.
% ?- test2(A, fail).
%@ A = 2 ;
%@ A = 3.
The reader (read_term/3 and friends) do not wrap anything. ISO defines that a naked variable X in a goal position is equivalent to call(X)
. SWI-Prolog compiles both a naked variable and call(X) to the same virtual machine code and the decompiler (listing/1, clause/2) thus produce the same term, wrapping the variable in call/1.
@j4n_bur53 wants to see the decompiler preserving the input. For dynamic clauses I think that is even demanded by ISO. SWI-Prolog doesn’t do this though. It sometimes produces small variations based on canonicalization that happens during compilation. Another example is X == a
vs a == X
, i.e., comparing a variable against a constant. When decompiling this is always presented as X == a
.
Not really, it could also remove call/1 in the input. Like for example input:
negation(X) :- call(X), !, fail.
negation(_).
And then during listing/[0,1]
:
negation(X) :- X, !, fail.
negation(_).
But I refrained from doing something that would affect listing/[0,1] or
retract/1, clause/2. I now do it under the hood, and it gives me some
performance boost, although I need more deref(). Its a sneaky
compilation optimization of call/1 which removes it from the generated code,
by placing a naked variable in the generated code. But its now realized so
that the end-user doesn’t know. Except for a little performance gain.
Without this optimization, the Lion and Unicorn example:
/* Dogelog Player 1.1.4, JDK 21 */
?- time((between(1,1000000,_), solve(_), fail; true)).
% Zeit 7086 ms, GC 1 ms, Lips 13124484, Uhr 09.11.2023 13:11
true.
With this optimization, the Lion and Unicorn example:
/* Dogelog Player 1.1.4, JDK 21 */
?- time((between(1,1000000,_), solve(_), fail; true)).
% Zeit 6891 ms, GC 0 ms, Lips 9577724, Uhr 10.11.2023 10:40
true.
Note the LIPS went down, because call/1 is not anymore present,
and thus not anymore counted. But the performance gain is not that
big. Still thinking about other ways to opimitze, the Lion and
Unicorn example is quite tricky to optimize concerning the Prolog
system that runs it. That will be a nice task for the Christmas & New
Years holidays, to squeeze the lemon further!
Both call/1 and a naked variable are handled in the VM using a (the same) single instruction, so it really doesn’t matter how you write the code. I like decompiling to call/1 as it makes the meta-call explicit and also makes the effective scope of the cut explicit. First I was a bit puzzled by your initial result, but after using listing/1 it was immediately clear why it was processed as it is.