Prolog POST handler

389 Views Asked by At

i'm pretty new to Prolog and i have some troubles with POST. This is my Prolog form:

form([action='/game', method='POST'], [
              p([], [
                label([for=fromX],'From X'),
                input([name=fromX, type=textarea])
              ]),
              p([], [
                label([for=fromY],'From Y'),
                input([name=fromY, type=textarea])
              ]),
              p([], [
                label([for=toX],'To X'),
                input([name=toX, type=textarea])
              ]),
              p([], [
                label([for=toY],'To Y'),
                input([name=toY, type=textarea])
              ]),
              p([], input([name=submit, type=submit, value='Submit'], []))
            ])

and this is my handler:

answer('/game', Request) :-
 memberchk(search(Search), Request),
 memberchk(toX=ToX, Search),
 memberchk(toY=ToY, Search),
 memberchk(fromX=FromX, Search),
 memberchk(fromYy=FromY, Search),
 whiteTurn(ToX/ToY, FromX/FromY, White_N),
 game_page(White_N).

When I hit submit button, I get

Internal server error goal unexpectedly failed

Can someone please help me with how to make this handler work properly? Now I only need to proceed data from form to whiteTurn function, I will deal with other exceptions later.

Here is executable example, with same error:

:- use_module(library('http/thread_httpd')).
:- use_module(library('http/html_write')).
:- use_module(library('http/http_session')).
:- use_module(library('http/http_error')).

server :-
  server(3000).

server(Port) :-
  http_server(answer,
        [ port(Port),
          timeout(20)
        | []
        ]).

 answer(Request) :-
  memberchk(path(Path), Request),
  answer(Path, Request).

 answer(/, _Request) :-
   title_page.

 answer('/game', Request) :-
  memberchk(search(Search), Request),
  memberchk(toX=ToX, Search),
  memberchk(toY=ToY, Search),
  memberchk(fromX=FromX, Search),
  memberchk(fromYy=FromY, Search),
  whiteTurn(ToX/ToY, FromX/FromY, White_N),
  game_page(White_N).

  title_page:-
   reply_html_page(
        title('Draughts'),
        [
         h1('Draughts'),
   form([action='/game', method='POST'], [
          p([], [
            label([for=fromX],'From X'),
            input([name=fromX, type=textarea])
          ]),
          p([], [
            label([for=fromY],'From Y'),
            input([name=fromY, type=textarea])
          ]),
          p([], [
            label([for=toX],'To X'),
            input([name=toX, type=textarea])
          ]),
          p([], [
            label([for=toY],'To Y'),
            input([name=toY, type=textarea])
          ]),
          p([], input([name=submit, type=submit, value='Submit'], []))
        ])
    ]).

 whiteTurn(X/Y, A/B, WHITE_N):-
  WHITE = [ 2/1,4/1,6/1,8/1,
    1/2,3/2,5/2,7/2,
    2/3,4/3,6/3,8/3],
  M = [ 1/1,2/1,3/1,4/1,5/1,6/1,7/1,8/1,
    1/2,2/2,3/2,4/2,5/2,6/2,7/2,8/2,
    1/3,2/3,3/3,4/3,5/3,6/3,7/3,8/3,
    1/2,2/2,3/2,4/2,5/2,6/2,7/2,8/2,
    1/4,2/4,3/4,4/4,5/4,6/4,7/4,8/4,
    1/5,2/5,3/5,4/5,5/5,6/5,7/5,8/5,
    1/6,2/6,3/6,4/6,5/6,6/6,7/6,8/6,
    1/7,2/7,3/7,4/7,5/7,6/7,7/7,8/7,
    1/8,2/8,3/8,4/8,5/8,6/8,7/8,8/8 ],
    (   member(X/Y, M), (X =:= A + 1; X =:= A - 1), Y =:= B - 1, 
    member(A/B, WHITE) ->  
    delete(WHITE, X/Y, WHITE_M), WHITE_N is [A/B|WHITE_M]; 
    WHITE_N = WHITE ).

    game_page(White_N):-
     reply_html_page(
        title('Draughts'),
        [
         h1('Draughts'),
     form([action='/game', method='POST'], [
          p([], [
            label([for=fromX],'From X'),
            input([name=fromX, type=textarea])
          ]),
          p([], [
            label([for=fromY],'From Y'),
            input([name=fromY, type=textarea])
          ]),
          p([], [
            label([for=toX],'To X'),
            input([name=toX, type=textarea])
          ]),
          p([], [
            label([for=toY],'To Y'),
            input([name=toY, type=textarea])
          ]),
          p([], input([name=submit, type=submit, value='Submit'], []))
        ])
      ]).
1

There are 1 best solutions below

3
On BEST ANSWER

To locate the precise cause of failure in Prolog programs, use the powerful technique of declarative debugging.

To do this, add the following definition to your program:

:- op(950,fy, *).

*_.

Now, using (*)/1 lets you generalize away goals in a very convenient way, by simply using * in front. This amounts to commenting the goal out, but is more convenient because it also works for the last goal of a clause, without having to change , to . in the preceding goal.

So, in your case, a quick look confirms that the failure occurs in answer/2. Logically, failure means that your program is too specific. Thus, you can generalize it for example like this:


answer('/game', Request) :-
  * memberchk(search(Search), Request),
  * memberchk(toX=ToX, Search),
  * memberchk(toY=ToY, Search),
  * memberchk(fromX=FromX, Search),
  * memberchk(fromYy=FromY, Search),
  * whiteTurn(ToX/ToY, FromX/FromY, White_N),
  game_page(White_N).

I am using strikethrough font to indicate that the goal can be simply discarded when reading this snippet.

If you try it now with the thus modified program, it succeeds!

Obviously, though, the program is now much too general.

So, you can again make it more specific by systematically re-introducing the goals you have generalized away.

Here is a first shot:

answer('/game', Request) :-
  memberchk(search(Search), Request),
  * memberchk(toX=ToX, Search),
  * memberchk(toY=ToY, Search),
  * memberchk(fromX=FromX, Search),
  * memberchk(fromYy=FromY, Search),
  * whiteTurn(ToX/ToY, FromX/FromY, White_N),
  game_page(White_N).

Here, I have (arbitrarily) re-introduced the first goal.

Now, the whole query again fails!

Thus, we have found a definite cause of this failure: To make the whole query succeed, we must either introduce additional clauses, or generalize this particular goal.

In other words, this all means: A term of the form search(S) does not occur in Request in this case!

I leave correcting this as an exercise.

If you are ever unsure what the actual Request contains, you can use this definition instead to emit the request:

answer('/game', Request) :-
        format("Content-type: text/plain~n~n"),
        maplist(portray_clause, Request).