Prolog - Confusion With Order of Printing in Recursion - prolog

Given the following program:
postIt([]).
postIt([c|R]) :- postIt(R), !, nl.
postIt([X|R]) :- postIt(R), write(X).
Query:
?- postIt([a,b,c,d,e]).
Trace:
[trace] ?-
| postIt([a,b,c,d,e]).
Call: (8) postIt([a, b, c, d, e]) ? creep
Call: (9) postIt([b, c, d, e]) ? creep
Call: (10) postIt([c, d, e]) ? creep
Call: (11) postIt([d, e]) ? creep
Call: (12) postIt([e]) ? creep
Call: (13) postIt([]) ? creep
Exit: (13) postIt([]) ? creep
Call: (13) write(e) ? creep
e
Exit: (13) write(e) ? creep
Exit: (12) postIt([e]) ? creep
Call: (12) write(d) ? creep
d
Exit: (12) write(d) ? creep
Exit: (11) postIt([d, e]) ? creep
Call: (11) nl ? creep
Exit: (11) nl ? creep
Exit: (10) postIt([c, d, e]) ? creep
Call: (10) write(b) ? creep
b
Exit: (10) write(b) ? creep
Exit: (9) postIt([b, c, d, e]) ? creep
Call: (9) write(a) ? creep
a
Exit: (9) write(a) ? creep
Exit: (8) postIt([a, b, c, d, e]) ? creep
true.
I don't quite understand why the output is 'ed' 'ba'. I figured that the program would print 'ab' skip 'c' then print 'de'. I am hoping someone may be able to clarify this for me.

Before I address the actual question, one additional point: Please consider using more_readable_names_with_underscores insteadOfStickingItAllTogetherLikeThis. Thus, I suggest for example the name post_it/1.
Next, to make our life simpler, I will only consider the following fragment of your code:
post_it([]).
post_it([X|R]) :- post_it(R), write(X).
That is, I have simply omitted the second clause entirely.
What do you expect now from the query ?- post_it([a,b,c,d]).? Is it abcd?
No, obviously it isn't:
?- post_it([a,b,c,d]).
dcba
Why? In your case, since you are using the impure predicate write/1, the reason for this can only be understood procedurally, that is taking into account the actual execution strategy of Prolog.
The execution strategy of Prolog is called, among other names, depth first search with chronological backtracking. When you have a clause like:
a :- b, c.
then, when a/0 is executed, b/0 is invoked first, and only if b/0 succeeds, c/0 is invoked.
Thus, consider for example the simpler query:
?- post_it([a,b]).
First, post_it([b]) is invoked, and it emits b (Exercise: Why?). Only then, a is emitted, because write(a) occurs as the second goal in post_it/1.
Obviously, in such simple cases, we can still somehow grasp the procedural definition. The major deficit of this is that this quickly becomes way too complex to understand, and so I can only recommend to avoid side-effects: They will invariably make your code too hard to understand, and you are already seeing the first signs of this.
Recommendation: Work in the pure subset of Prolog. In your case, consider the following relation between lists:
without_c(Ls0, Ls) :-
tfilter(dif(c), Ls0, Ls).
This uses tfilter/3 from Ulrich Neumerkel's library(reif) to declaratively describe the relation between two lists, where the second list is the same as the first, but without any occurrence of the atom c.
Example query:
?- without_c([a,b,c,d], Ls).
Ls = [a, b, d].
Much more general cases work too, for example:
?- length(Ls0, _), without_c(Ls0, Ls).
Ls0 = Ls, Ls = [] ;
Ls0 = [c],
Ls = [] ;
Ls0 = Ls, Ls = [_7366],
dif(_7366, c) ;
Ls0 = [c, c],
Ls = [] .
Note that such relations can be easily tested, because the arguments can be reasoned about explicitly, much in contrast to output that only occurs on the terminal. In addition, this program admits a declarative reading, freeing you from many operational considerations.
Note also an additional problem of your original definition: Due to the usage of !/0, it has become extremely hard to predict the effect of removing the second clause. The resulting program is not more specific (as would be expected otherwise), but actually emits solutions that were previously not emitted!

Related

Difference between two Implementation of even and odd in Prolog

i have two implementation of Prolog , the Function is to decide if the given number is odd or even
the first one works correctly
even1(0).
even1(X) :- X>0 ,X1 is X-1, odd1(X1).
odd1(1).
odd1(X) :- X>1 , X1 is X-1, even1(X1).
even1(2) returns true
but the second one doesnt work correctly
even2(0).
even2(X) :- X>0 , odd2(X-1).
odd2(1).
odd2(X) :- X>1 , even2(X-1).
even2(2) returns false
can anyone explain to me whats is the difference between the two of them ?
Prolog is a relational language, not a functional language. Thus, when you call odd2(X-1), the predicate argument, X-1, is not evaluated as an expression but interpreted as a compound term:
?- functor(X-1, Name, Arity).
Name = (-),
Arity = 2.
You can check what happens when Prolog proves a query by using your system trace functionality:
?- trace.
true.
[trace] ?- even2(2).
Call: (8) even2(2) ? creep
Call: (9) 2>0 ? creep
Exit: (9) 2>0 ? creep
Call: (9) odd2(2-1) ? creep
Call: (10) 2-1>0 ? creep
Exit: (10) 2-1>0 ? creep
Call: (10) even2(2-1-1) ? creep
Call: (11) 2-1-1>0 ? creep
Fail: (11) 2-1-1>0 ? creep
Fail: (10) even2(2-1-1) ? creep
Fail: (9) odd2(2-1) ? creep
Fail: (8) even2(2) ? creep
false.
Note that the expression 2-1-1 evaluates to zero but, being a compound term, the call even2(2-1-1) doesn't unify with your base case for the predicate, even2(0):
?- even2(2-1-1) = even2(0).
false.
?- 2-1-1 = 0.
false.
Therefore, Prolog tries the second clause and the call eventually fails the X>0 check. Note that >/2, by being an arithmetic comparison predicate, it does evaluate its arguments prior to the actual comparison.

Prolog - infinite loop

I want to check if element is in the middle of list.
I search middle element and next I check if is a member of list, but I get infinite loop.
My predicates:
remove_first([_,H1|T], [H1|T]).
remove_last([_],[]).
remove_last([H|T], [H|T2]) :- remove_last(T, T2).
remove_first_and_last([X],[X]).
remove_first_and_last(In, Out) :-
remove_first(In, Out1),
remove_last(Out1, Out).
middle([X], [X]).
middle(In, X) :-
remove_first_and_last(In, Out),
middle(Out, X).
member(X, [X|_]).
member(X, [_|T]) :- member(X, T).
is_middle(X, In) :-
middle(In, Out),
member(X, Out), !.
And when I call is_middle(1,[2,1,3]) then I get true.
But when I call is_middle(1,[2,2,3]) then I don't get a result. Interpreter don't interrupt the processing.
In a situation as yours, you have two options. Either wade through walls of text of traces as you can see in another answer, or try to reduce first what you have to understand. I prefer the latter for I don't like to read much.
But your major problem is this. You said:
And when I call is_middle(1,[2,1,3]) then I get true.
Yes, Prolog found a solution, but it did not find it once but infinitely many times. Just hit SPACE or ; to see this:
?- is_middle(1,[2,1,3]).
true
; true
; true
; true
; true
; ... .
So, already your first query was problematic. The best way to observe this, is to add false to this query:
?- is_middle(1,[2,1,3]), false.
loops.
Now, let's try to reduce the size of the query. We can narrow it down to:
?- is_middle(1,[1]), false.
loops.
With this we can now look at your program. Before anything else I'll remove the cut. It is misplaced anyway.
To understand what is actually happening, I will narrow down your program by inserting false into it. With these extra goals it is possible to eliminate a lot of unnecessary detail. And still, the remaining program called a failure-slice is of relevance to us, if it is still looping.
remove_first_and_last([X],[X]).
remove_first_and_last(In, Out) :- false,
remove_first(In, Out1),
remove_last(Out1, Out).
middle([X], [X]) :- false.
middle(In, X) :-
remove_first_and_last(In, Out),
middle(Out, X), false.
is_middle(X, In) :-
middle(In, Out), false,
member(X, Out).
Compare this to your original program! Much less reading. To fix the problem you have to fix something in the remaining fragment. I suggest to remove the fact remove_first_and_last([X],[X]). This fact suggests that something is removed, but for this very case, nothing is removed.
For a solution using a dcg directly:
is_middle(E, Es) :-
phrase(middle(E), Es).
middle(E) --> [E].
middle(E) --> [_], middle(E), [_].
That is as short as it can get, but it has a tiny problem: It does not compute the answer determinately. You can see this by looking at the answer:
?- is_middle(1, [2,1,3]).
true
; false.
This ; false is an indication that Prolog was not able to finish the computation determinately. In other words, some space is left. You might be tempted to use a cut. Resist!
If you are really into speed, take the fastest version:
is_middle(X, Xs) :-
Xs = [_|Cs],
middle_el(Cs, Xs, X).
middle_el([], [X|_], X).
middle_el([_,_|Cs], [_|Xs], X) :-
middle_el(Cs, Xs, X).
In case you want #DanielLyons' interpretation which admits even-length lists to have two middle elements, see how easy it is to adopt above grammar definition. Simply add the following two rules:
middle(E) --> [E,_].
middle(E) --> [_,E].
Alternatively, combine all four rules into one:
middle(E) --> [E] | [E,_] | [_,E] | [_], middle(E), [_].
For the fastest solution, things are a bit more complex ...
is_middle_dl(X, Xs) :-
Xs = [_|Cs],
middle_el_dl(Cs, Xs, X).
middle_el_dl([], [X|_], X).
middle_el_dl([_|Cs], Xs, X) :-
middle_el_dl2(Cs, Xs, X).
middle_el_dl2([], [A,B|_], X) :-
( X = A ; X = B ).
middle_el_dl2([_|Cs], [_|Xs], X) :-
middle_el_dl(Cs, Xs, X).
To check it, I use:
?- length(Xs, N), N mod 2 =:= 0, is_middle_dl(X, Xs).
Xs = [X,_A], N = 2
; Xs = [_A,X], N = 2
; Xs = [_A,X,_B,_C], N = 4
; Xs = [_A,_B,X,_C], N = 4
; Xs = [_A,_B,X,_C,_D,_E], N = 6
; Xs = [_A,_B,_C,X,_D,_E], N = 6
; Xs = [_A,_B,_C,X,_D,_E,_F,_G], N = 8
; Xs = [_A,_B,_C,_D,X,_E,_F,_G], N = 8
; Xs = [_A,_B,_C,_D,X,_E,_F,_G,_H,_I], N = 10
; Xs = [_A,_B,_C,_D,_E,X,_F,_G,_H,_I], N = 10
; ... .
Debugging Prolog takes some different skills, so let's take the long road there.
First, let's notice something interesting about your two sample queries. The first one succeeds, and it should; the second one should fail, but instead it loops. This tidbit is a clue: it suggests that we're trying to handle a false case. This is a common mistake among people using Prolog after other languages. In Prolog, it's often enough to be explicit about successful cases and just let failures happen through failed unifications.
The standard tool for debugging Prolog is trace/0. The idea is, you activate trace mode and then run your query, like this:
?- trace, is_middle(1,[2,2,3]).
The trouble with trace/0 is that it can take some effort to understand what's happening with it. Each line starts with one of these four verbs: call, exit, redo, or fail. Then there's a number which indicates the nesting level of the call. The call and redo verbs tell you that you're entering a computation; exit and fail tell you a computation is ceasing and the nesting level is about to decrease. Call/exit are the normal case, fail/redo are what makes Prolog special, the non-determinism. In general, an infinite loop will look like some prefix of meaningful work (or possibly not) followed by an endlessly repeating chunk of output from trace. And we see that here. Prefix:
Call: (8) is_middle(1, [2, 2, 3]) ? creep
Call: (9) middle([2, 2, 3], _G1194) ? creep
Call: (10) remove_first_and_last([2, 2, 3], _G1194) ? creep
Call: (11) remove_first([2, 2, 3], _G1194) ? creep
Exit: (11) remove_first([2, 2, 3], [2, 3]) ? creep
Call: (11) remove_last([2, 3], _G1197) ? creep
Call: (12) remove_last([3], _G1190) ? creep
Exit: (12) remove_last([3], []) ? creep
Exit: (11) remove_last([2, 3], [2]) ? creep
Exit: (10) remove_first_and_last([2, 2, 3], [2]) ? creep
Repeating chunk:
Call: (10) middle([2], _G1200) ? creep
Exit: (10) middle([2], [2]) ? creep
Exit: (9) middle([2, 2, 3], [2]) ? creep
Call: (9) member(1, [2]) ? creep
Call: (10) member(1, []) ? creep
Fail: (10) member(1, []) ? creep
Fail: (9) member(1, [2]) ? creep
Redo: (10) middle([2], _G1200) ? creep
Call: (11) remove_first_and_last([2], _G1200) ? creep
Exit: (11) remove_first_and_last([2], [2]) ? creep
Now you can see it would be much easier to trigger the bad behavior just with this query:
[trace] ?- is_middle(2,[3]).
Call: (7) is_middle(2, [3]) ? creep
Call: (8) middle([3], _G398) ? creep
Exit: (8) middle([3], [3]) ? creep
Call: (8) member(2, [3]) ? creep
Call: (9) member(2, []) ? creep
Fail: (9) member(2, []) ? creep
Fail: (8) member(2, [3]) ? creep
Redo: (8) middle([3], _G398) ? creep
Call: (9) remove_first_and_last([3], _G398) ? creep
Exit: (9) remove_first_and_last([3], [3]) ? creep
Call: (9) middle([3], _G401) ? creep
Exit: (9) middle([3], [3]) ? creep
Exit: (8) middle([3], [3]) ? creep
Call: (8) member(2, [3]) ? creep
Call: (9) member(2, []) ? creep
Fail: (9) member(2, []) ? creep
Fail: (8) member(2, [3]) ? creep
Redo: (9) middle([3], _G401) ? creep
Now it should be clear that the problem has to do with the interplay of middle/2, remove_first_and_last/2 and member/2. Your definition of member/2 is exactly the standard definition so it probably isn't to blame. Now, interestingly, you have middle/2 calling both itself and remove_first_and_last/2. And both middle/2 and remove_first_and_last/2 have an identical clause: m([X], [X]).
This kind of thing is a great generator of infinite recursion, because the first thing middle/2 does in its second clause is exactly what it just tried to do and failed with its own first clause. So it can find itself entering a recursive call in the second clause with exactly the same state it had in an earlier failed call to itself.
The solution is to look at remove_first_and_last/2 and realize that your first clause there does not actually remove the first and last element. Removing the remove_first_and_last([X], [X]) clause fixes the code:
[trace] ?- is_middle(2,[3]).
Call: (7) is_middle(2, [3]) ? creep
Call: (8) middle([3], _G398) ? creep
Exit: (8) middle([3], [3]) ? creep
Call: (8) member(2, [3]) ? creep
Call: (9) member(2, []) ? creep
Fail: (9) member(2, []) ? creep
Fail: (8) member(2, [3]) ? creep
Redo: (8) middle([3], _G398) ? creep
Call: (9) remove_first_and_last([3], _G398) ? creep
Call: (10) remove_first([3], _G398) ? creep
Fail: (10) remove_first([3], _G398) ? creep
Fail: (9) remove_first_and_last([3], _G398) ? creep
Fail: (8) middle([3], _G398) ? creep
Fail: (7) is_middle(2, [3]) ? creep
false.
Both your tests also now work:
?- is_middle(1,[2,1,3]).
true.
?- is_middle(1,[2,2,3]).
false.
I think you added the base case here out of a sense of duty to have one. But the reality is that if you have a list of one element, it should fail to unify with remove_first_and_last/2 under any circumstance. This is very similar to handling an error case explicitly with Prolog, which tends to interfere with the working of the machinery.
Now, one thing that's missing is, how do you want to handle even-length lists? What you have right now won't, with or without my change. Even-length lists don't have a middle element; is that what you intend? I suspect it isn't, because of the appearance of member/2 in is_middle/2.
Comments on is_middle/2
What you have here could be restructured like so:
is_middle(X, In) :- middle(In, [X]).
Usage of member/2 isn't buying you anything because middle/2 can't ever produce a non-singleton list in its second argument. But, if it did, because you had even-length lists, it would be profitable. You could even make this code work that way by adding a third clause to middle/2:
middle([X,Y], [X,Y]).
Now see middle/2 works on even-length lists like so:
?- middle([2,1,3,4], X).
X = [1, 3] ;
false.
Now the cut gets you into trouble though. For instance, 1 and 3 are both is_middle/2:
?- is_middle(1, [2,1,3,4]).
true.
?- is_middle(3, [2,1,3,4]).
true.
Unfortunately though, if you ask for middle elements, you just have 1:
?- is_middle(X, [2,1,3,4]).
X = 1.
What happened to 3? You prevented it from being generated with your cut. I am not sure why the cut is here. I think you must have put it in to try and control the infinite recursion, but it doesn't help you, so get rid of it.
Debugging by random addition of cuts is generally not a great idea. A much better approach is using Ulrich Neumerkel's failure slice approach (see this paper or search the tag for more information).
DCG bonus
You can rephrase remove_first_and_last/2 as a DCG rule:
remove_first_and_last --> remove_first, remove_last.
Pretty cool, huh? :) That's because the kind of input/output threading you're doing in that rule exactly what DCG rules get transformed into.
Summary of changes
remove_first_and_last(In, Out) :-
remove_first(In, Out1),
remove_last(Out1, Out).
middle([X], [X]).
middle([X,Y], [X,Y]).
middle(In, X) :-
remove_first_and_last(In, Out),
middle(Out, X).
is_middle(Item,List) :-
append(Left,[Item|Right],List),
length(Left,X),
length(Right,X).
Complex solutions are bad solutions, my friend.
?- is_middle(X,[1,2,3,4,5]).
X = 3 ;
false.
Fully reversible predicate:
?- is_middle(3,L).
L = [3] ;
L = [_G13, 3, _G19] ;
L = [_G13, _G19, 3, _G25, _G28] ;

How to check if the name is in a list that is recognized by its similar term in a predicate?

Suppose, I have a prolog predicate such as:
name(music,[jazz,blues,classical]).
and what I want is to check membership of say jazz and return me true if in music?
So far, I did this:
ismember(X,Y):-imember(X,name(Y,Z)),write(Z).
imember(X,[_|Tail]):-imember(X,Tail).
imember(X,[X|_]).
But it isn't working.
?- ismember(jazz,music).
false.
And it isn't writing the write(Z) part.
In the visible part of the following fragment there is an error. Not only does your program fail, also the following generalization fails:
:- op(950, fy, *).
*(_).
ismember(X,Y):-
imember(_/*X*/,name(_/*Y*/,Z)).
imember(X,[_|Tail]):-
* imember(X,Tail).
imember(X,[_/*X*/|_]).
?- ismember(X, Y).
The generalization has been obtained by replacing some variables by _, and by removing one goal with *. It generalizes as much as possible. That is, any further generalization would make the goal succeed. And there is this nice property that holds in (pure, monotonic) Prolog:
If a generalization fails (for a specific query), then also the original program fails (for that same query).
That's the nice property that somehow establishes causality between a generalized fragment and the original program. If you want to remove the error, something in the generalized program has to be changed. Or conversely: If you make changes that still permit to get the generalization, then you have not fixed the error.
With this in mind,when searching for such a fragment, there is no need to "understand" the actual program. It suffices to guess and generalize mindlessly as long as this is possible.
Now, if we look at that generalization note that
the arguments of ismember/2 are completely ignored!
The problem is that the name(Y,Z) that you pass in imember/2 predicate isn't a list. You could simply write:
ismember(X,Y):-name(Y,Z),imember(X,Z),write(Z).
imember(X,[_|Tail]):-imember(X,Tail).
imember(X,[X|_]).
Example:
?- ismember(jazz,music).
[jazz,blues,classical]
true.
the ismember/2 predicate second parameter is a list , and you are not passing a list
here is a trace
[trace] ?- ismember(jazz,music).
Call: (8) ismember(jazz, music) ? creep
Call: (9) imember(jazz, name(music, _6828)) ? creep
Fail: (9) imember(jazz, name(music, _6828)) ? creep
Fail: (8) ismember(jazz, music) ? creep
false.
#coder answer is a correct way
or you can simply use the member/2 predicate as follows:
first define your list in the database:
music([jazz,blues,classical]).
now we have our music types list , next we write the rule
ismusicmember(X) :- music(L) , member(X,L),write(L).
music(L) to assign the variable L to our music list
member(X,L) the member/2 predicate check whether X is in the list or not
and running a query
?- ismusicmember(jazz).
[jazz,blues,classical]
true .
a trace:
[trace] ?- ismusicmember(jazz).
Call: (8) ismusicmember(jazz) ? creep
Call: (9) music(_7376) ? creep
Exit: (9) music([jazz, blues, classical]) ? creep
Call: (9) lists:member(jazz, [jazz, blues, classical]) ? creep
Exit: (9) lists:member(jazz, [jazz, blues, classical]) ? creep
Call: (9) write([jazz, blues, classical]) ? creep
[jazz,blues,classical]
Exit: (9) write([jazz, blues, classical]) ? creep
Exit: (8) ismusicmember(jazz) ? creep
true .

Definition of a path/trail/walk

Many predicates define some kind of an acyclic path built from edges defined via a binary relation, quite similarly to defining transitive closure. A generic definition is thus called for.
Note that the notions defined in graph theory do not readily match what is commonly expected. Most notably, we are not interested in the edges' names.
Worse, also graph theory has changed a bit, introducing the notion of walk, noting
Traditionally, a path referred to what is now usually known as an open walk. Nowadays, when stated without any qualification, a path is usually understood to be simple, meaning that no vertices (and thus no edges) are repeated. (The term chain has also been used to refer to a walk in which all vertices and edges are distinct.)
So my question is: How to name and define this functionality?
What I have done so far is to define:
path(Rel_2, Path, X0,X)
The first argument has to be the continuation of the relation which is an incomplete goal that lacks two further arguments. Then comes either the Path or the pair of vertices.
Example usage
n(a, b).
n(b, c).
n(b, a).
?- path(n,Xs, a,X).
Xs = [a], X = a
; Xs = [a, b], X = b
; Xs = [a, b, c], X = c
; false.
Implementation
:- meta_predicate(path(2,?,?,?)).
:- meta_predicate(path(2,?,?,?,+)).
path(R_2, [X0|Ys], X0,X) :-
path(R_2, Ys, X0,X, [X0]).
path(_R_2, [], X,X, _).
path(R_2, [X1|Ys], X0,X, Xs) :-
call(R_2, X0,X1),
non_member(X1, Xs),
path(R_2, Ys, X1,X, [X1|Xs]).
non_member(_E, []).
non_member(E, [X|Xs]) :-
dif(E,X),
non_member(E, Xs).
How about defining path/4 like this?
path(R_2, Xs, A,Z) :- % A path `Xs` from `A` to `Z` is ...
walk(R_2, Xs, A,Z), % ... a walk `Xs` from `A` to `Z` ...
all_dif(Xs). % ... with no duplicates in `Xs`.
To aid universal termination, we swap the two goals in above conjunction ...
path(R_2, Xs, A,Z) :-
all_dif(Xs), % enforce disequality ASAP
walk(R_2, Xs, A,Z).
... and use the following lazy implementation of all_dif/1:
all_dif(Xs) :- % enforce pairwise term inequality
freeze(Xs, all_dif_aux(Xs,[])). % (may be delayed)
all_dif_aux([], _).
all_dif_aux([E|Es], Vs) :-
maplist(dif(E), Vs), % is never delayed
freeze(Es, all_dif_aux(Es,[E|Vs])). % (may be delayed)
walk/4 is defined like path/4 and path/5 given by the OP:
:- meta_predicate walk(2, ?, ?, ?).
walk(R_2, [X0|Xs], X0,X) :-
walk_from_to_step(Xs, X0,X, R_2).
:- meta_predicate walk_from_to_step(?, ?, ?, 2).
walk_from_to_step([], X,X, _).
walk_from_to_step([X1|Xs], X0,X, R_2) :-
call(R_2, X0,X1),
walk_from_to_step(Xs, X1,X, R_2).
IMO above path/4 is simpler and more approachable, particularly for novices. Would you concur?
I want to focus on naming the predicate.
Unlike maplist/2,
the argument order isn't of primary importance here.
The predicate name should make the meaning of the respective arguments clear.
So far, I like path_from_to_edges best, but it has its pros and cons, too.
path_from_to_edges(Path,From,To,Edges_2) :-
path(Edges_2,Path,From,To).
Let's pick it apart:
pro: path is a noun, it cannot be mis-read a verb. To me, a list of vertices is implied.
pro: from stands for a vertex, and so does to.
con: edges is somewhat vague, but using lambdas here is the most versatile choice.
con: According to Wikipedia, a path is a trail in which all vertices (except possibly the first and last) are distinct. So that would need to be clarified in the description.
Using lambdas for a lists of neighbor vertices Ess:
?- Ess = [a-[b],b-[c,a]],
From = a,
path_from_to_edges(Path,From,To,\X^Y^(member(X-X_neibs,Ess),member(Y,X_neibs))).
Ess = [a-[b],b-[c,a]], From = a, To = a, Path = [a]
; Ess = [a-[b],b-[c,a]], From = a, To = b, Path = [a,b]
; Ess = [a-[b],b-[c,a]], From = a, To = c, Path = [a,b,c]
; false.
Edit 2015-06-02
Another shot at better naming! This leans more on the side of maplist/2...
graph_path_from_to(P_2,Path,From,To) :-
path(P_2,Path,From,To).
Here, graph, of course, is a noun, not a verb.
Regarding the meaning of "path": paths definitely should allow From=To and not exclude that by default (with pairwise term inequalities). It is easy to exclude this with an additional dif(From,To) goal, but not the other way round.
I do not see the reason to define in path/4 the arguments "start node" and "end node". It seems that a simple path/2 with the rule and the list of nodes must be enough.
If the user wants a list starting with some node (by example, 'a'), he can query the statement as: path( some_rule, ['a'|Q] ).
A user could, by example, request for path that have length 10 in the way: length(P,10), path( some_rule, P).
* Addendum 1 *
Some utility goals can be easily added, but they are not the main subject. Example, path/3 with start node is:
path( some_rule, [start|Q], start ) :-
path ( some_rule, [start|Q ] ).
* Addendum 2 *
Addition of last node as argument could give the false idea that this argument drives the algorithm, but it doesn't. Assume by example:
n(a, b).
n(a, c).
n(a, d).
and trace algorithm execution for the query:
[trace] ?- path( n, P, X, d ).
Call: (6) path(n, _G1025, _G1026, d) ? creep
Call: (7) path(n, _G1107, _G1026, d, [_G1026]) ? creep
Exit: (7) path(n, [], d, d, [d]) ? creep
Exit: (6) path(n, [d], d, d) ? creep
P = [d],
X = d ;
Redo: (7) path(n, _G1107, _G1026, d, [_G1026]) ? creep
Call: (8) n(_G1026, _G1112) ? creep
Exit: (8) n(a, b) ? creep
Call: (8) non_member(b, [a]) ? creep
Call: (9) dif:dif(b, a) ? creep
Exit: (9) dif:dif(b, a) ? creep
Call: (9) non_member(b, []) ? creep
Exit: (9) non_member(b, []) ? creep
Exit: (8) non_member(b, [a]) ? creep
Call: (8) path(n, _G1113, b, d, [b, a]) ? creep
Call: (9) n(b, _G1118) ? creep
Fail: (9) n(b, _G1118) ? creep
Fail: (8) path(n, _G1113, b, d, [b, a]) ? creep
Redo: (9) non_member(b, []) ? creep
Fail: (9) non_member(b, []) ? creep
Fail: (8) non_member(b, [a]) ? creep
Redo: (8) n(_G1026, _G1112) ? creep
Exit: (8) n(a, c) ? creep
Call: (8) non_member(c, [a]) ? creep
Call: (9) dif:dif(c, a) ? creep
Exit: (9) dif:dif(c, a) ? creep
Call: (9) non_member(c, []) ? creep
Exit: (9) non_member(c, []) ? creep
Exit: (8) non_member(c, [a]) ? creep
Call: (8) path(n, _G1113, c, d, [c, a]) ? creep
Call: (9) n(c, _G1118) ? creep
Fail: (9) n(c, _G1118) ? creep
Fail: (8) path(n, _G1113, c, d, [c, a]) ? creep
Redo: (9) non_member(c, []) ? creep
Fail: (9) non_member(c, []) ? creep
Fail: (8) non_member(c, [a]) ? creep
Redo: (8) n(_G1026, _G1112) ? creep
Exit: (8) n(a, d) ? creep
Call: (8) non_member(d, [a]) ? creep
Call: (9) dif:dif(d, a) ? creep
Exit: (9) dif:dif(d, a) ? creep
Call: (9) non_member(d, []) ? creep
Exit: (9) non_member(d, []) ? creep
Exit: (8) non_member(d, [a]) ? creep
Call: (8) path(n, _G1113, d, d, [d, a]) ? creep
Exit: (8) path(n, [], d, d, [d, a]) ? creep
Exit: (7) path(n, [d], a, d, [a]) ? creep
Exit: (6) path(n, [a, d], a, d) ? creep
P = [a, d],
X = a .
as you can see, in this case algorithm fails to brute force.
For this reason, if algorithm is not improved, I suggest do not add "end node" as "path" argument.

Natural language interpreter in Prolog does not work

I'm having a problem in Prolog. I'm trying to write a converter that converts simple english sentences into commands in Prolog.
Im trying to create a text adventure game using the tutorial here.
My problem is this: After starting the main command loop, when entering a sentence and hitting the "enter" button, Prolog will simply jump into the next line, seemingly not executing the command at all. It does not matter how often I enter a full-stop. Before using this language converter, everything worked just fine and the game was playable using commands. The problem must be within this part of the code. More precisely, I think the part for reading lines or the get_command(X) function are most likely not working.
I'm using SWI-Polog by the way, in case that is of importance (some people add this info to their questions).
Since I can't spot the mistake myself, I will try to post the relevant code.
First the main command loop:
command_loop:-
write('Welcome to Nani Search'), nl,
look,nl,
repeat,
write('>nani> '),
get_command(X),
do(X), nl,
end_condition(X).
And now the converter (the get_command(X) function is at the very bottom):
% Natural language converter
command([V], InList):- verb(V, InList-[]).
verb(look, [look|X]-X).
verb(look, [look,around|X]-X).
verb(look, [glotz,ma,alde|X]-X).
verb(list_possessions, [inventory|X]-X).
verb(end, [end|X]-X).
verb(end, [quit|X]-X).
verb(end, [good,bye|X]-X).
command([V,O], InList) :-
verb(Object_Type, V, InList-S1),
object(Object_Type, O, S1-[]).
verb(place, goto, [go,to|X]-X).
verb(place, goto, [go|X]-X).
verb(place, goto, [move,to|X]-X).
% Exceptions for rooms with two words
verb(place, goto, [X|Y]-[X|Y]):- room(X).
verb(place, goto, [dining,room|Y]-[dining,room|Y]).
verb(thing, take, [take|X]-X).
verb(thing, drop, [drop|X]-X).
verb(thing, drop, [put|X]-X).
verb(thing, turn_on, [turn,on|X]-X).
verb(thing, turn_off, [turn,off|X]-X).
object(Type, N, S1-S3) :-
det(S1-S2),
noun(Type, N, S2-S3).
object(Type, N, S1-S2) :-
noun(Type, N, S1-S2).
det([the|X]- X).
det([a|X]-X).
det([an|X]-X).
% Exceptions for rooms with two words
noun(place, R, [R|X]-X):- room(R).
noun(place, 'dining room', [dining,room|X]-X).
% Exceptions for things with two words
noun(thing, T, [T|X]-X):- location(object(T,_),_).
noun(thing, T, [T|X]-X):- have(object(T,_)).
noun(thing, 'washing machine', [washing,machine|X]-X).
noun(thing, flashlight, [light|X]-X):- have(object(flashlight,_)).
noun(thing, light, [light|X]-X).
% read a line of words from the user
read_list(L) :-
write('> '),
read_line(CL),
wordlist(L,CL,[]), !.
read_line(L) :-
get0(C),
buildlist(C,L).
buildlist(13,[]) :- !.
buildlist(C,[C|X]) :-
get0(C2),
buildlist(C2,X).
wordlist([X|Y]) --> word(X), whitespace, wordlist(Y).
wordlist([X]) --> whitespace, wordlist(X).
wordlist([X]) --> word(X).
wordlist([X]) --> word(X), whitespace.
word(W) --> charlist(X), {name(W,X)}.
charlist([X|Y]) --> chr(X), charlist(Y).
charlist([X]) --> chr(X).
chr(X) --> [X],{X>=48}.
whitespace --> whsp, whitespace.
whitespace --> whsp.
whsp --> [X], {X<48}.
% Return a command
get_command(C) :-
read_list(L),
command(CL,L),
C =.. CL, !.
get_command(_) :-
write('I don''t understand'), nl, fail.
And finally, the do-function from the command loop:
do(goto(X)):-goto(X),!.
do(go(X)):-goto(X),!.
do(take(X)):-take(X),!.
do(put(X,Y)):-put(X),!.
do(turn_on(X)):-turn_on(X),!.
do(turn_off(X)):-turn_off(X),!.
do(inventory):-inventory,!.
do(list_things(X)):-list_things(X),!.
do(look):-look,!.
do(end).
do(_) :-
write('Invalid command').
By converting the natural language sentences into these commands, the program is supposed to start the respective function. It is supposed to work like this: When you enter go to the office. the converter is supposed to transform the frase into the command goto(office). When one writes take the flashlight it is supposed to convert it to take(flashlight) . When one writes look around. it should be converted to look. The converted command should then be send to the command loop and be executed via do(X) (As seen in the do-function, X must be command like goto(office).
I hope it is clear what my question is.
I also made a trace. The command loop is being started normally. This is what happens after the end of the command loop (the write('>nani> ') still being part of it).
Call: (7) write('>nani> ') ? creep
>nani>
Exit: (7) write('>nani> ') ? creep
Call: (7) get_command(_G3903) ? creep
Call: (8) read_list(_G3903) ? creep
Call: (9) write('> ') ? creep
>
Exit: (9) write('> ') ? creep
Call: (9) read_line(_G3903) ? creep
Call: (10) get0(_G3903) ? creep
|:
Then I'm able to enter a new command. By simply pressing the Enter button without giving any input, it will always do the following:
Exit: (10) get0(10) ? creep
Call: (10) buildlist(10, _G3904) ? creep
Call: (11) get0(_G3906) ? creep
|:
This is being repeated whenever I hit enter. When I enter a random letter or multiple letters before pressing enter, the value of the first get0 will change, but nothing else.
Depending on which letters I write there sometimes is a different result though. Here are two examples:
For example when I try writing dsf, this will happen:
|: dsf
Exit: (10) get0(100) ? skip
Call: (10) buildlist(100, _G3904) ? fail
Fail: (9) read_line(_G3903) ? creep
Fail: (8) read_list(_G3903) ? creep
Redo: (7) get_command(_G3903) ? creep
Call: (8) write('I don\'t understand') ? creep
I don't understand
Exit: (8) write('I don\'t understand') ? creep
Call: (8) nl ? creep
Exit: (8) nl ? creep
᠀ Call: (8) fail ? creep
Fail: (8) fail ? creep
Fail: (7) get_command(_G3903) ? creep
Redo: (7) repeat ? creep
Exit: (7) repeat ? creep
Call: (7) write('>nani> ') ? creep
>nani>
Exit: (7) write('>nani> ') ? creep
Call: (7) get_command(_G3903) ? creep
Call: (8) read_list(_G3903) ? creep
Call: (9) write('> ') ? creep
>
Exit: (9) write('> ') ? creep
Call: (9) read_line(_G3903) ? creep
Call: (10) get0(_G3903) ? creep
|:
Other input like apg will have the following result:
|: apg
Exit: (17) get0(97) ? print
Exit: (17) get0(97) ? goals
[17] get0(97)
[16] buildlist(10, [10|_G3915])
[15] buildlist(10, [10, 10|_G3915])
[14] buildlist(10, [10, 10, 10|_G3915])
[13] buildlist(10, [10, 10, 10, 10|_G3915])
Exit: (17) get0(97) ? creep
Call: (17) buildlist(97, _G3915) ? creep
Call: (18) get0(_G3927) ? creep
And when entering longer commands, random or also something like go to the office., the program will shut down completely, without a comment. This shutdown only happens while the trace is activated. When it is not, commands like go to the office. will, again, simply make the program jump to the next line, seemingly not doing anything.
What might also be interesting is the fact that, after starting the command loop, the program takes a long time to shut down. The following message is being displayed:
Waiting for Prolog. Close again to force termination ..
Since I'm really new to Prolog, I'm not quite sure how to interpret this. To me the reaction to the random letters as input is competely random. Maybe someone else has a clue.
I would apreciate it a lot, if someone could help me out. I hope it's not too big of a mistake.
Regards :)

Resources