How can I inspect WAM code in SICStus Prolog - prolog

In the context of hacking clpz on sicstus-prolog I want to glimpse at the warren-abstract-machine code generated by SICStus Prolog.
As an example, let's dissect the following predicate!
is_list([]).
is_list([_|Es]) :- is_list(Es).
Here's what I'm doing now:
Split the 2 clauses of is_list/1 into 2 separate predicates and prepend 2 dummy clauses:
is_list__clause1(dummy1). % dummy clause
is_list__clause1([]).
is_list__clause2(dummy2). % dummy clause
is_list__clause2([_|Es]) :- is_list(Es).
(Ab-)use the SICStus prolog-toplevel like so:
| ?- is_list__clause1(X).
X = dummy1 ? t
…
0x7eff37281300: GET_NIL_X0
0x7eff37281304: PROCEED
0x7eff37281308: END_OF_CLAUSEQ user:is_list__clause1/1
…
| ?- is_list__clause2(X).
X = dummy2 ? t
…
0x7eff37281150: GET_LIST_X0
0x7eff37281154: U2_VOID_XVAR 1,x(0)
0x7eff37281160: EXECUTEQ user:is_list/1
0x7eff37281170: END_OF_CLAUSEQ user:is_list__clause2/1
…
This output—albeit somewhat cryptic—is giving me a feel of what's going on at the WAM level. I like!
But there has got to a simpler way... please help!

There is a simpler way: the undocumented, unsupported, library(disassembler).
You can use this for programmatically getting information about first-argument indexing in addition to the WAM instructions. See the source for more information.
| ?- use_module(library(disassembler)).
% ...
yes
| ?- [user].
% compiling user...
| foo([],Ys,Ys). foo([X|Xs],Ys,[X|Zs]) :- foo(Xs,Ys,Zs). end_of_file.
% compiled user in module user, 89 msec 599696 bytes
yes
| ?- disassemble(foo/3).
% Predicate: user:foo/3 (user)
% Varcase: [4343940512-4343958960,4346212208-4343221120]
% Lstcase: [4346212212]
% Switch: [[]=4343940516], default: failcode
% clause indexed [var,number,atom,structure] (user)
% 4343940512: 'GET_NIL_X0'
% 4343940516: 'GET_X_VALUE_PROCEED'(x(1),x(2))
% 4343940528: 'END_OF_CLAUSEQ'(user:foo/3)
% clause indexed [var,list] (user)
% 4346212208: 'GET_LIST_X0'
% 4346212212: 'U2_XVAR_XVAR'(x(3,0),x(0,0))
% 4346212224: 'GET_LIST'(x(2))
% 4346212232: 'U2_XVAL_XVAR'(x(3),x(2,0))
% 4346212244: 'EXECUTE'(user:foo/3)
% 4346212256: 'END_OF_CLAUSEQ'(user:foo/3)
yes
| ?-

Related

How to compile a prolog question correctly?

I am working on a prolog problem and need some help here.
/*Write a predicate listtran(L,E) which translates a list of Latin number words
* to the corresponding list of English number words. */
%% predicate
listtran(L,E).
%% clauses
tran(unus,one).
tran(duo,two).
tran(tres,three).
tran(quattuor,four).
tran(quinque,five).
tran(sex,six).
tran(septem,seven).
tran(octo,eight).
tran(novem,nine).
%% rules
% base case: empty list
listtran([], []).
% inductive cases:
listtran([L | T0], [E | T1]) :-
tran(L, E), % translate the head of the list
listtran(T0, T1). % translate the tail of the list, using recursion
What is needed to be written in predicates and query to test:
?- listtran([unus,novem,duo],X).
should give:
X = [one,nine,two].
and
?- listtran(X,[one,seven,six,two]).
it should return:
X = [unus,septem,sex,duo].
Also, what can be done to avoid the error message:
Clauses of listtran/2 are not together in the source-file
Thanks!
That is a discontigous predicate error.
Prolog is complaining that all the clauses of a predicate are not defined in one place. You should just delete the listtrans(L, E).(why is it even there?) at the start and the rest should work fine.
An explanation of the error: https://stackoverflow.com/a/40614467/4437190

prolog finding cardinality of a list

I have written a Prolog code to find the cardinality of a list ie number of distinct elements. It gives correct output but it runs multiple times and I cant seem to get my head around it. I have used the debugger but cant understand whats wrong
member(A, [A|_]).
member(A, [_|L]) :- member(A, L).
crdnlty([],0).
crdnlty([A|R],N) :-
(
\+ member(A, R),
crdnlty(R, N1),
N is N1+1
);
(
member(A, R),
crdnlty(R, N)
).
member checks if A is present in the remaining list.
if its not present ie it is the last occurrence of that element cardinality is increased by 1.
for example if i run the query
crdnlty([1,2,1,1], N).
it returns
N = 2 ;
N = 2 ;
false.
but it should return
N = 2 ;
false.
This is not answer but just a testing suggestion that doesn't fit in a comment.
Besides the unwanted duplicated solution, there's also the question on how to test the predicate. A simple alternative solution is to use the ISO Prolog standard predicate sort/2 and the de facto standard predicate length/2. The alternative solution could be:
cardinality(List, Cardinality) :-
sort(List, Sorted),
length(Sorted, Cardinality).
We can use this alternative solution to define a property that your solution must comply with that allows to QuickCheck your solution (ignoring for now the unwanted non-determinism):
property(List) :-
once(crdnlty(List, C)),
sort(List, S),
length(S, C).
Using the QuickCheck implementation provided by Logtalk's lgtunit tool (which you can run in most Prolog systems; in this example I will be using GNU Prolog):
$ gplgt
...
| ?- {lgtunit(loader)}.
...
% (0 warnings)
(578 ms) yes
| ?- lgtunit::quick_check(property(+list(integer)), [n(2000)]).
% 2000 random tests passed
(1589 ms) yes
Of course, QuickCheck can show bugs but cannot prove their absence. That said, a distinctive feature of Logtalk's QuickCheck implementation is that it tries trivial/corner cases for the specified types before generating random values. This help in ensuring that the random testing will not miss obvious test cases (as we illustrate next).
What happens if we test instead the solution provided by Scott Hunter?
| ?- lgtunit::quick_check(property(+list(integer)), [n(2000)]).
* quick check test failure (at test 1 after 0 shrinks):
* property([])
no
In fact, his solution doesn't take into account that the list may be empty. Assuming that's considered a bug, adding the missing clause:
crdnlty([], 0).
Re-testing:
| ?- lgtunit::quick_check(property(+list(integer)), [n(2000)]).
% 2000 random tests passed
(1509 ms) yes
It might be better to build a list of distinct elements & yield its length for the cardinality:
crdnlty([A|R],N) :- distinct(R,N,[A],1).
% distinct(L,N,DL,DN): There are N distinct values in list L+DL,
% assuming there are DN distinct values in list DL alone.
distinct([],N,_,N).
distinct([A|R],N,DL,DN) :-
(
\+ member(A, DL),
DN1 is DN+1,
distinct(R, N, [A|DL], DN1)
);
(
member(A, DL),
distinct(R, N, DL, DN)
).

Argument - simple prolog

Want to expand the argument q(M,N):- that should evaluate true , only if
we can express M as sum of two numbers , that also these same two numbers would give the the product of N. Meaning something like A+B=M and A*B=N (M,N>0 both Integers)
So I've tried something like :
sum(A,B,M) :- M is A+B.
prod(A,B,N) :- N is A*B.
q(M,N) :- sum(A,B,M),
prod(A,B,N).
But yeah not a great plan.
some expected outcomes should be:
| ?- q(18,45).
yes
| ?- q(45,18).
no
| ?- q(4,4).
yes
| ?- q(5,5).
no
| ?- q(16,64).
yes
| ?- q(12,25).
no
| ?- q(25,24).
yes
| ?- q(36,120).
no
| ?- q(100,2499).
yes
| ?- q(100,267).
no
| ?- q(653,98770).
yes
| ?- q(653,98880).
no
A very basic solution for your problem, using between/3 from swi prolog, without heavilly modifing your program is:
sum(A,B,M) :- M is A+B.
prod(A,B,N) :- N is A*B.
q(M,N) :-
between(0,1000,A),
between(0,1000,B),
sum(A,B,M),
prod(A,B,N).
In this case, all numbers between 0 and 1000 are considered for A and B. However, there are some weakness. For instance, values for A and B can be exchanged (q(18,45) succeeds for A = 3 and B = 15 and A = 15 and B = 3). To remove this redundancy you can impose B < A. To further improve the algorithm, you can set a range for A and B based on the value of the sum and the product. Certainly both A and B must be less than the value M in your code. Like:
q(M,N) :-
between(0,M,A),
between(0,A,B),
M is A+B,
N is A*B.
You can add further constraints to improve the performances, for instance considering cases where the product is 0 etc...
You can use also clpfd library to solve this problem.

Prolog- repeat input until

I want to create a predicate that only accepts a specific input from the user and it will keep asking for the right input if the user gives the wrong input.
I've created this, but its not completed because it does not ask for the new input if its wrong:
askchar(X):- write('give char'),nl, get_char(X), test(X).
test(X):- X=a, write('ok'). %accepts a
test(X):- X='1', write('ok'). %accepts 1
test(X):- write('wrong input. try again'),nl.
in systems lacking a decent tail recursive optimization, processing side effects can be conveniently done with a failure driven loop
1 ?- [user].
|: askchar(C) :- repeat, get(C), (C = 0'a ; C = 0'1, ! ; fail).
% user://1 compiled 0.07 sec, 2 clauses
true.
2 ?- askchar(X).
|: 5
|: a
X = 97 .
Here is what I got:
askChar(Char) :- get_char(Char), test(Char), write('This is the right char, thank you.'), !.
askChar(Char) :- write('That is wrong char!'), askChar(Char).
test(s).
It asks again and again until the char s is typed in.

Convert peano number s(N) to integer in Prolog

I came across this natural number evaluation of logical numbers in a tutorial and it's been giving me some headache:
natural_number(0).
natural_number(s(N)) :- natural_number(N).
The rule roughly states that: if N is 0 it's natural, if not we try to send the contents of s/1 back recursively to the rule until the content is 0, then it's a natural number if not then it's not.
So I tested the above logic implementation, thought to myself, well this works if I want to represent s(0) as 1 and s(s(0)) as 2, but I´d like to be able to convert s(0) to 1 instead.
I´ve thought of the base rule:
sToInt(0,0). %sToInt(X,Y) Where X=s(N) and Y=integer of X
So here is my question: How can I convert s(0) to 1 and s(s(0)) to 2?
Has been answered
Edit: I modified the base rule in the implementation which the answer I accepted pointed me towards:
decode(0,0). %was orignally decode(z,0).
decode(s(N),D):- decode(N,E), D is E +1.
encode(0,0). %was orignally encode(0,z).
encode(D,s(N)):- D > 0, E is D-1, encode(E,N).
So I can now use it like I wanted to, thanks everyone!
Here is another solution that works "both ways" using library(clpfd) of SWI, YAP, or SICStus
:- use_module(library(clpfd)).
natsx_int(0, 0).
natsx_int(s(N), I1) :-
I1 #> 0,
I2 #= I1 - 1,
natsx_int(N, I2).
No problemo with meta-predicate nest_right/4 in tandem with
Prolog lambdas!
:- use_module(library(lambda)).
:- use_module(library(clpfd)).
:- meta_predicate nest_right(2,?,?,?).
nest_right(P_2,N,X0,X) :-
zcompare(Op,N,0),
ord_nest_right_(Op,P_2,N,X0,X).
:- meta_predicate ord_nest_right_(?,2,?,?,?).
ord_nest_right_(=,_,_,X,X).
ord_nest_right_(>,P_2,N,X0,X2) :-
N0 #= N-1,
call(P_2,X1,X2),
nest_right(P_2,N0,X0,X1).
Sample queries:
?- nest_right(\X^s(X)^true,3,0,N).
N = s(s(s(0))). % succeeds deterministically
?- nest_right(\X^s(X)^true,N,0,s(s(0))).
N = 2 ; % succeeds, but leaves behind choicepoint
false. % terminates universally
Here is mine:
Peano numbers that are actually better adapted to Prolog, in the form of lists.
Why lists?
There is an isomorphism between
a list of length N containing only s and terminating in the empty list
a recursive linear structure of depth N with function symbols s
terminating in the symbol zero
... so these are the same things (at least in this context).
There is no particular reason to hang onto what 19th century mathematicians
(i.e Giuseppe Peano )
considered "good structure structure to reason with" (born from function
application I imagine).
It's been done before: Does anyone actually use Gödelization to encode
strings? No! People use arrays of characters. Fancy that.
Let's get going, and in the middle there is a little riddle I don't know how to
solve (use annotated variables, maybe?)
% ===
% Something to replace (frankly badly named and ugly) "var(X)" and "nonvar(X)"
% ===
ff(X) :- var(X). % is X a variable referencing a fresh/unbound/uninstantiated term? (is X a "freshvar"?)
bb(X) :- nonvar(X). % is X a variable referencing an nonfresh/bound/instantiated term? (is X a "boundvar"?)
% ===
% This works if:
% Xn is boundvar and Xp is freshvar:
% Map Xn from the domain of integers >=0 to Xp from the domain of lists-of-only-s.
% Xp is boundvar and Xn is freshvar:
% Map from the domain of lists-of-only-s to the domain of integers >=0
% Xp is boundvar and Xp is boundvar:
% Make sure the two representations are isomorphic to each other (map either
% way and fail if the mapping gives something else than passed)
% Xp is freshvar and Xp is freshvar:
% WE DON'T HANDLE THAT!
% If you have a freshvar in one domain and the other (these cannot be the same!)
% you need to set up a constraint between the freshvars (via coroutining?) so that
% if any of the variables is bound with a value from its respective domain, the
% other is bound auotmatically with the corresponding value from ITS domain. How to
% do that? I did it awkwardly using a lookup structure that is passed as 3rd/4th
% argument, but that's not a solution I would like to see.
% ===
peanoify(Xn,Xp) :-
(bb(Xn) -> integer(Xn),Xn>=0 ; true), % make sure Xn is a good value if bound
(bb(Xp) -> is_list(Xp),maplist(==(s),Xp) ; true), % make sure Xp is a good value if bound
((ff(Xn),ff(Xp)) -> throw("Not implemented!") ; true), % TODO
length(Xp,Xn),maplist(=(s),Xp).
% ===
% Testing is rewarding!
% Run with: ?- rt(_).
% ===
:- begin_tests(peano).
test(left0,true(Xp=[])) :- peanoify(0,Xp).
test(right0,true(Xn=0)) :- peanoify(Xn,[]).
test(left1,true(Xp=[s])) :- peanoify(1,Xp).
test(right1,true(Xn=1)) :- peanoify(Xn,[s]).
test(left2,true(Xp=[s,s])) :- peanoify(2,Xp).
test(right2,true(Xn=2)) :- peanoify(Xn,[s,s]).
test(left3,true(Xp=[s,s,s])) :- peanoify(3,Xp).
test(right3,true(Xn=3)) :- peanoify(Xn,[s,s,s]).
test(f1,fail) :- peanoify(-1,_).
test(f2,fail) :- peanoify(_,[k]).
test(f3,fail) :- peanoify(a,_).
test(f4,fail) :- peanoify(_,a).
test(f5,fail) :- peanoify([s],_).
test(f6,fail) :- peanoify(_,1).
test(bi0) :- peanoify(0,[]).
test(bi1) :- peanoify(1,[s]).
test(bi2) :- peanoify(2,[s,s]).
:- end_tests(peano).
rt(peano) :- run_tests(peano).

Resources