序幕 POST 幕

Prolog POST handler

我是 Prolog 的新手,我在使用 POST 时遇到了一些麻烦。 这是我的 Prolog 表格:

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'], []))
            ])

这是我的处理程序:

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).

当我点击提交按钮时,我得到

Internal server error goal unexpectedly failed

有人可以帮助我如何使这个处理程序正常工作吗?现在我只需要将数据从表单处理到whiteTurn函数,其他的异常我会在后面处理。

这是可执行的例子,有同样的错误:

:- 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'], []))
        ])
      ]).

要在 Prolog 程序中找到 失败 的确切原因,请使用强大的 声明式调试技术

为此,请将以下定义添加到您的程序中:

:- op(950,fy, *).

*_.

现在,使用 (*)/1 可以让您以一种非常方便的方式 概括出 目标,只需在前面使用 *。这相当于将目标注释掉,但更方便,因为它也适用于子句的最后一个目标,而无需将前面的目标中的 , 更改为 .

因此,在您的情况下,快速查看确认故障发生在 answer/2 中。从逻辑上讲,失败意味着您的程序过于具体。因此,您可以 概括 它,例如像这样:


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).

我正在使用 删除线 字体来表示在阅读此代码段时可以简单地 丢弃 目标。

如果您现在尝试使用修改后的程序,它成功

不过,显然,该程序现在过于笼统

因此,您可以通过系统地重新引入您概括的目标,再次使其更加具体。

这是第一张照片:

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).

在这里,我(随意地)重新引入了第一个目标。

现在,整个查询再次失败

因此,我们找到了这个失败的明确原因:要使整个查询成功,我们要么引入额外的子句,要么泛化 这个特定的目标。

换句话说,这一切意味着:在这种情况下,search(S) 形式的术语不会出现 Request 中!

我将更正此作为练习。

如果您不确定实际 Request 包含什么,您可以使用此定义来发出请求:

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