循环直到 Prolog 中的结果为假

Looping until the result is false in Prolog

我正在尝试使用 Prolog 执行一个循环,直到谓词的输出为假。我正在实施“文字”游戏,这里是我正在使用的一些相关谓词:

available_length(L):-
       word(W,_),          %Passing through every word W resulting from predicate word(W,C). 
       atom_chars(W,Y),    %Adding the letters of the word W to list Y.
       length1(Y,L).       %Finding the length of the list.
length1([],0).
length1([_|Tail],L):-
       length1(Tail,Prev),
       L is Prev + 1.  

前面的谓词基本上以一个整数作为输入,并检查谓词word(W, C)中是否存在长度等于该整数的词(其中W是词,C是类别) .下面显示的是这个谓词的知识库:


word(horse,animals).
word(panda,animals).
word(hello,greetings).
word(banana,fruits).
word(bison,animals).
word(hoard,collections).

这就是“available_length”谓词的工作原理:


available_length(L): succeeds if there are words in the KB with length L.
Examples:
?- available_length(5).
true.    %becuase there exists words with length 5 in the KB(horse,panda,hello,bison,hoard).

?- available_length(9).
false.    %becuase there don't exist words with the length 9 in the KB.

游戏开始时,它会要求用户选择一个类别以及他选择的单词的长度。然后根据他的选择,从他输入的类别中随机选择一个单词,游戏开始为用户提供等于(单词长度 + 1)的单词猜测次数。但是,如果用户输入的单词长度在他选择的类别中不存在,则应提示他选择的长度不存在的消息,并允许他再次选择,直到他输入一个长度存在。

我实现了底部显示的另一个辅助谓词,它使用上面的谓词“available_length”来检查用户输入的长度是否存在,如果不存在,则应该显示他提示信息如上。

这是执行游戏的谓词的相关部分:


play:-
    write('The available categories are: '),  %Not implemented yet.
    nl,
    write('Choose a category: '),
    nl,
    read(Category),
    nl,
    write('Choose a length: '),
    nl,
    read(WordLength),      %Takes the length as an input from the user.
    check_length,          %Executes the helper predicate"check_length"shown below.
    Guesses is WordLength + 1,   %The rest is executed only if "check_length" succeeds.
    write('Game started. You have '),
    write(Guesses),
    write(' guesses.'),

问题是我如何不断提示用户消息,直到“available_length”谓词的输出变为真(意味着用户输入了正确的长度)。我已经尝试了以下辅助谓词,但它没有用,它会提示消息是否输入存在的长度:


check_length:-
    read(WordLength),
    (available_length(WordLength) = true;   %Loops until the length entered does exist.
     (write('There are no words with this length.'),  %Otherwise,this prompt message appear. 
      nl,
      write('Choose a length: '),     %The user is allowed to choose a length again.
      check_length)
    ).

有人知道它是如何完成的吗?另一个问题是如何执行一个谓词,该谓词在用户从 KB 的谓词中选择的类别中选择一个随机词。例如,如果他选择“动物”类别,则应随机选择三个词之一:马、熊猫和野牛)。类别再次显示如下:


word(horse,animals).
word(panda,animals).
word(hello,greetings).
word(banana,fruits).
word(bison,animals).
word(hoard,collections).


要检查给定长度的单词的可用性,您需要知道它属于哪个类别。另外,要确定原子的长度,可以使用 ISO 谓词 atom_length/2:

available_length(Category, Length) :-
    (   word(Word, Category),
        atom_length(Word, Length)
    ->  true ).

读取用户输入的词条,可以使用谓词:

input(Prompt, Term) :-
    write(Prompt),
    read(Term).

要重复输入直到输入 有效的单词类别 ,请使用谓词:

input_category(Category) :-
    (   input('Choose a category:\n', Category),
        word(_, Category)
    ->  true
    ;   write('Invalid category!\n'),
        input_category(Category) ).

示例:

?- input_category(C).
Choose a category:
|: planets.
Invalid category!
Choose a category:
|: animals.

C = animals.

要重复输入直到输入 有效字长 ,对于给定类别,使用谓词:

input_length(Category, Length) :-
    (   input('Choose a length:\n', Length),
        available_length(Category, Length)
    ->  true
    ;   format('Category "~w" has no word with this length.\n', [Category]),
        input_length(Category, Length) ).

示例:

?- input_length(animals, L).
Choose a length:
|: 9.
Category "animals" has no word with this length.
Choose a length:
|: 6.
Category "animals" has no word with this length.
Choose a length:
|: 5.

L = 5.

从给定的类别中选择一个随机词,您可以使用谓词random_member/2:

random_word(Category, Word) :-
    findall(Word, word(Word, Category), Words),
    random_member(Word, Words).

示例:

?- random_word(animals, W).
W = panda.

?- random_word(animals, W).
W = horse.

?- random_word(animals, W).
W = bison.

SWI-Prolog定义random_member/2如下:

random_member(X, List) :-
    must_be(list, List),
    length(List, Len),
    Len > 0,
    N is random(Len),
    nth0(N, List, X).

你的问题太长了。太长了。您还已经做出了几个有问题的设计选择。

The previous predicate basically takes as an input an integer and checks whether there exists a word in the predicate word(W, C) having a length equal to that integer(where W is the word and C is the category).

使用您的数据库,在 Prolog 中执行此操作的简单方法是:

available_length(Length) :-
    \+ \+ ( word(W, _), atom_length(W, Length) ).

你在数据库中寻找一个 Length 长的单词,如果找到了,你就成功了。没有循环,没有递归,只有逻辑。查查“否定即失败”是什么意思!

The question is how do I keep prompting the user with the message until the output of the "available_length" predicate becomes true

至少有两种方法可以做到这一点。一个是古老的“failure-driven 循环”,看看它是什么意思。为此,您确实需要 repeat/0。为了示例跳过所有 writes:

?- repeat,
   (   read(N),
       available_length(N)
   ->  true,
       !
   ;   fail
   ).
|: 3.
|: 7.
|: 5.

N = 5.

这也是字面意思你这个很长的问题的标题。

另一种方法是使用 this answer 向您展示的递归定义。如果你需要保持状态,你应该更喜欢递归定义而不是 failure-driven 循环。

有太多方法可以根据您的用例随机选择一个词。但这已经是一个新问题了,所以我不会在这里回答。