s-webber / projog

Prolog programming for the Java platform.
Apache License 2.0
37 stars 9 forks source link

"Expected list but got: VARIABLE" exception #177

Closed vladiulianbogdan closed 3 years ago

vladiulianbogdan commented 4 years ago

Hello,

I have tried to use Projog today and I have encountered the following problem.

I am using the following prolog code.

all_possibilities(List, Routes, Constraints, Result) :-
    length(Routes, LRoutes), 
    part(List, LRoutes, PartedList),
    insert_in_routes(PartedList, Routes, Result),
    same_path_constraints(Constraints, Result).
    % validate_result(TempResult, Result).

insert_in_routes([], [], []).
insert_in_routes([Head|PartedList], [HeadRoute|LRoutes], [R|Result]) :-
    possibilities(HeadRoute, Head, R),
    insert_in_routes(PartedList, LRoutes, Result).

possibilities(X, [], X).
% List with elements X, an array with elements Y, X must keep order and Y must insert in all possibilities
possibilities(FixedList, [Head|Elements], Res) :-
    select(Head, Result, FixedList),
    possibilities(Result, Elements, Res).

same_path_constraints([], _).
same_path_constraints([HeadD|Dependencies], Routes) :-
    dependecy_exist_in_route(HeadD, Routes),
    same_path_constraints(Dependencies, Routes).

dependecy_exist_in_route([Start, End], [Head|Routes]) :-
    indexOf(Head, Start, IndexStart),
    indexOf(Head, End, IndexEnd),
    IndexStart < IndexEnd.

dependecy_exist_in_route([Start, End], [Head|Routes]) :-
    \+(indexOf(Head, Start, IndexStart)),
    \+(indexOf(Head, End, IndexEnd)),
    dependecy_exist_in_route([Start, End], Routes).

part(List, N, Result) :-
    length(Result, N),
    concat_all(Result, List).

concat_all([], []).
concat_all([Head|List], Result2) :-
    append(Head, Result, Result2),
    concat_all(List, Result).

indexOf([Element|_], Element, 0):- !.
indexOf([_|Tail], Element, Index):-
  indexOf(Tail, Element, Index1),
  !,
  Index is Index1+1.

If I run the following query "all_possibilities([1, 2, 3, 4, 5, 6], [[11, 20, 31, 42], [41, 52], [12, 23]], [[1, 2], [3, 4]], Result)." in SWI-Prolog I do get an answer.

However when I run the following code in Java I get the exception.

        Projog p = new Projog();

        // Read Prolog facts and rules from a file to populate the "Projog" instance created in step 1.
        p.consultFile(new File("src/test.pl"));

        // Create a query that will use the facts read in step 2.
        QueryStatement s1 = p.query("all_possibilities([1, 2, 3, 4, 5, 6], [[11, 20, 31, 42], [41, 52], [12, 23]], [[1, 2], [3, 4]], X).");

        // Execute the query created in step 3.
        QueryResult r1 = s1.getResult();

        System.out.println(r1.next());
        System.out.println(r1.getTerm("X"));

The exception is:

Exception in thread "main" org.projog.core.ProjogException: Expected list but got: VARIABLE
    at org.projog.core.function.list.Select.getPredicate(Select.java:85)
    at org.projog.compiled_at_runtime.P4.retryRule1(P4.java:37)
    at org.projog.compiled_at_runtime.P4.evaluate(P4.java:90)
    at org.projog.compiled_at_runtime.P3.retryRule1(P3.java:39)
    at org.projog.compiled_at_runtime.P3.evaluate(P3.java:91)
    at org.projog.compiled_at_runtime.P3.retryRule1(P3.java:53)
    at org.projog.compiled_at_runtime.P3.evaluate(P3.java:91)
    at org.projog.compiled_at_runtime.P3.retryRule1(P3.java:53)
    at org.projog.compiled_at_runtime.P3.evaluate(P3.java:91)
    at org.projog.compiled_at_runtime.P0.retryRule0(P0.java:58)
    at org.projog.compiled_at_runtime.P0.evaluate(P0.java:116)
    at org.projog.api.QueryResult.doFirstEvaluationOfQuery(QueryResult.java:81)
    at org.projog.api.QueryResult.next(QueryResult.java:68)
    at Main.main(Main.java:167)

One important thing to mention is that I am using version 0.3.0 because I was not able to import 0.4.0 using maven.

        <dependency>
            <groupId>org.projog</groupId>
            <artifactId>projog-core</artifactId>
            <version>0.3.0</version>
        </dependency>

Thank you very much for this project, it is really useful!

s-webber commented 4 years ago

Hello,

Thank you for raising this issue.

The cause of this problem is how the select/3 built-in predicate is implemented in Projog. The Projog version does not work when the second argument is a variable.

Expected behaviour:

?- select(a, Result, [x,y,z]).

Result = [a,x,y,z]

yes

Result = [x,a,y,z]

yes

Result = [x,y,a,z]

yes

Result = [x,y,z,a]

yes

Actual behaviour:

?- select(a, Result, [x,y,z]).

Expected list but got: VARIABLE

I have attached a zip file - issue117.zip - containing a Maven project that demonstrates a workaround for this. The project contains a class named com.example.SelectBugFix which provides a new implementation for select/3 that fixes this bug. The src/main/resources/selectbugfix-projog-bootstrap.pl file configures Projog to use SelectBugFix for select/3, instead of the version provided by Projog. The com.example.Issue117Example class references selectbugfix-projog-bootstrap.pl when creating the Projog object.

Running com.example.Issue117Example produces the output:

true
.(.(11, .(20, .(31, .(42, [])))), .(.(41, .(52, [])), .(.(6, .(5, .(3, .(4, .(1, .(2, .(12, .(23, [])))))))), [])))
[[11,20,31,42],[41,52],[6,5,3,4,1,2,12,23]]

I suggest you add SelectBugFix and selectbugfix-projog-bootstrap.pl to your project and configure it in the same way as is done in Issue117Example. If you'd like to move SelectBugFix to a different package (instead of com.example) then you will also need to update the package name referenced in selectbugfix-projog-bootstrap.pl.

I hope this workaround is satisfactory for you. I will include this bugfix in a future version of Projog, at which point you will no longer need this workaround.

Thanks again for raising this issue. If there is anymore I can do to help then please let me know.

s-webber commented 3 years ago

Thank you for raising this issue. I have included a fix for this in the latest version of Projog - 0.4.0.

There have been a few changes in this latest version of Java (e.g. package structure has been reorganised, moved from Java 7 to Java 8, minor changes to the API). The following projects provide examples of how the latest version of Projog can be used to call Prolog from Java.

https://github.com/s-webber/prolog-wumpus-world https://github.com/s-webber/prolog-expert-system https://github.com/s-webber/projog-examples/tree/master/calling-prolog-from-java

I have attached the following ZIP file demonstrating how the Prolog code you included in the description of this issue can be called from Java:

projog-issue-177.zip

If you have anymore questions about Projog then please raise a new issue and I will take a look.

Thanks.