SWI Prolog-是否有条件?

SWI Prolog-是否有条件?,prolog,conditional-statements,Prolog,Conditional Statements,我想做一个prolog函数。函数读入一个句子,然后尝试提取一个关键字。如果找到关键字,它将打印一条消息。我希望它也打印一条消息,如果没有找到关键字。以下是我的例子: contains([word1|_]) :- write('word1 contained'). contains([Head|Tail]) :- Head \= word1, contains(Tail). contains([word2|_]) :- write('word2 contained'). contains([Hea

我想做一个prolog函数。函数读入一个句子,然后尝试提取一个关键字。如果找到关键字,它将打印一条消息。我希望它也打印一条消息,如果没有找到关键字。以下是我的例子:

contains([word1|_]) :- write('word1 contained').
contains([Head|Tail]) :- Head \= word1, contains(Tail).
contains([word2|_]) :- write('word2 contained').
contains([Head|Tail]) :- Head \= word2, contains(Tail).
contains([word3|_]) :- write('word3 contained').
contains([Head|Tail]) :- Head \= word3, contains(Tail).
上面的代码将检查并查看提取的单词是否存在。但如果没有包含“word1、word2或word3”这三个词,它就不会给出答案。有人知道我应该如何实施这个吗

我试着加上:

contains([_|_]) :- write('nothing contained'),nl.
contains([Head|Tail]) :- Head \= _, contains(Tail).

但很明显,这是错误的做法。

在命令式语言中,你会使用某种标志;例如:

found = False
for word in wordlist:
    if word in ('car', 'train', 'plane'):
        print "Found: " + word
        found = True
if not found:
    print "Nothing found."
您可以将此标志作为子句的另一个参数来实现:

% entry point
contains(X) :- contains(X, false).

% for each word...
contains([Word|Rest], Flag) :-
    Word = car   -> (write('Car found.'),   nl, contains(Rest, true)) ;
    Word = train -> (write('Train found.'), nl, contains(Rest, true)) ;
    Word = plane -> (write('Plane found.'), nl, contains(Rest, true)) ;
    contains(Rest, Flag).

% end of recursion
contains([], true).
contains([], false) :- write('Nothing found.'), nl.
如果要为每个单词创建不同的子句并抽象循环,请将中间部分更改为:

% for each word...
contains([Word|Rest], Flag) :-
    checkword(Word) -> NewFlag=true ; NewFlag=Flag,
    contains(Rest, NewFlag).

% and at the end:
checkword(car)   :- write('Car found.'), nl.
checkword(plane) :- write('Plane found.'), nl.
checkword(train) :- write('Train found.'), nl.

在命令式语言中,你会使用某种标志;例如:

found = False
for word in wordlist:
    if word in ('car', 'train', 'plane'):
        print "Found: " + word
        found = True
if not found:
    print "Nothing found."
您可以将此标志作为子句的另一个参数来实现:

% entry point
contains(X) :- contains(X, false).

% for each word...
contains([Word|Rest], Flag) :-
    Word = car   -> (write('Car found.'),   nl, contains(Rest, true)) ;
    Word = train -> (write('Train found.'), nl, contains(Rest, true)) ;
    Word = plane -> (write('Plane found.'), nl, contains(Rest, true)) ;
    contains(Rest, Flag).

% end of recursion
contains([], true).
contains([], false) :- write('Nothing found.'), nl.
如果要为每个单词创建不同的子句并抽象循环,请将中间部分更改为:

% for each word...
contains([Word|Rest], Flag) :-
    checkword(Word) -> NewFlag=true ; NewFlag=Flag,
    contains(Rest, NewFlag).

% and at the end:
checkword(car)   :- write('Car found.'), nl.
checkword(plane) :- write('Plane found.'), nl.
checkword(train) :- write('Train found.'), nl.

编写contains谓词主要部分的标准方法是:

contains([word1|_]) :- !, write('word1 contained').
contains([word2|_]) :- !, write('word2 contained').
contains([word3|_]) :- !, write('word3 contained').
contains([Head|Tail]) :- contains(Tail).
这意味着:

当你找到一个词时,不要再搜索了,这就是切题!接线员是接电话的。 当其他方法都不起作用时,它会在尾部递归。 若要在找不到任何结果的情况下添加答案,只需在递归调用上添加另一个cut,这样,只有在其他任何情况(包括递归)都不起作用时,才会调用后面的情况:

contains([word1|_]) :- !, write('word1 contained').
contains([word2|_]) :- !, write('word2 contained').
contains([word3|_]) :- !, write('word3 contained').
contains([Head|Tail]) :- contains(Tail), !.
contains(_) :- write('Nothing found').

编写contains谓词主要部分的标准方法是:

contains([word1|_]) :- !, write('word1 contained').
contains([word2|_]) :- !, write('word2 contained').
contains([word3|_]) :- !, write('word3 contained').
contains([Head|Tail]) :- contains(Tail).
这意味着:

当你找到一个词时,不要再搜索了,这就是切题!接线员是接电话的。 当其他方法都不起作用时,它会在尾部递归。 若要在找不到任何结果的情况下添加答案,只需在递归调用上添加另一个cut,这样,只有在其他任何情况(包括递归)都不起作用时,才会调用后面的情况:

contains([word1|_]) :- !, write('word1 contained').
contains([word2|_]) :- !, write('word2 contained').
contains([word3|_]) :- !, write('word3 contained').
contains([Head|Tail]) :- contains(Tail), !.
contains(_) :- write('Nothing found').

以下是我将如何做到这一点:

contains(Words) :-
    findall(Word,has(Words,Word),Sols),
    print_result(Sols).

% Word is a target word in the list Words
has(Words,Word) :-
    member(Word,Words), 
    member(Word,[word1,word2,word3]).

print_result([]) :- write('Nothing found.\n').
print_result([X|Xs]) :- print_sols([X|Xs]).

print_sols([]).
print_sols([X|Xs]) :-
    concat(X, ' contained.\n',Output),
    write(Output),
    print_sols(Xs).
这种方法的优点是它使用了更高级别的抽象,使得谓词更易于阅读。因为只有一个目标词列表,所以维护也变得更容易,而不必为每个新词添加单独的子句

诀窍在于has谓词使用member/2两次;一次从输入列表中选择一个项目,第二次测试它是否是目标词之一。将其用作findall/3的参数,然后生成在输入列表中找到的所有目标词


注意:print_结果中的[X | Xs]只需避免在第一个子句中使用剪切即可。

以下是我的操作方法:

contains(Words) :-
    findall(Word,has(Words,Word),Sols),
    print_result(Sols).

% Word is a target word in the list Words
has(Words,Word) :-
    member(Word,Words), 
    member(Word,[word1,word2,word3]).

print_result([]) :- write('Nothing found.\n').
print_result([X|Xs]) :- print_sols([X|Xs]).

print_sols([]).
print_sols([X|Xs]) :-
    concat(X, ' contained.\n',Output),
    write(Output),
    print_sols(Xs).
这种方法的优点是它使用了更高级别的抽象,使得谓词更易于阅读。因为只有一个目标词列表,所以维护也变得更容易,而不必为每个新词添加单独的子句

诀窍在于has谓词使用member/2两次;一次从输入列表中选择一个项目,第二次测试它是否是目标词之一。将其用作findall/3的参数,然后生成在输入列表中找到的所有目标词


注意:打印结果中的[X | Xs]避免了在第一个子句中使用剪切。

我认为liori给出了最好的答案。以下是在某些情况下可能有意义的稍微不同的方法,即:

生成打印输出 如果打印输出为空,则不打印任何内容,否则输出打印输出 以下内容适用于SWI Prolog,可能不适用于其他Prolog,因为它与_output_to/2一起使用:


我认为liori有最好的答案。以下是在某些情况下可能有意义的稍微不同的方法,即:

生成打印输出 如果打印输出为空,则不打印任何内容,否则输出打印输出 以下内容适用于SWI Prolog,可能不适用于其他Prolog,因为它与_output_to/2一起使用:


这个解决方案唯一的问题是,因为我的函数在程序结束前会被反复调用,当使用该函数并且我不写“word1”时,它会说:“找不到任何内容”。例如,如果我键入:word1,我会得到:“word1 contained”,如果我键入:word2,我会得到:“找不到任何内容”,如果我键入:word3,如果我再次键入word1,我会得到:“未找到任何内容”,我会得到:“word1已包含”。所以它只适用于第一个条件,之后所有其他条件似乎都被忽略了..哈,我不知怎么误读了你的代码。。。你想找到所有发生的事情。我会编辑我的答案。这个解决方案唯一的问题是,因为在程序结束之前,我的函数会被反复调用,当使用该函数时,我不会写“word1”,它会说:“找不到任何内容”。例如,如果我键入:word1,我会得到:“word1 contained”,如果我键入:word2,我会得到:“找不到任何内容”,如果我键入:word3,如果我再次键入word1,我会得到:“未找到任何内容”,我会得到:“word1已包含”。所以它只适用于第一个条件,之后所有其他条件似乎都被忽略了..哈,我不知怎么误读了你的代码。。。你想成为f
记录所有事件。我将编辑我的答案。使用cuts被认为是不好的。好吧,使用cuts确实意味着你的程序不再是一个纯粹的逻辑程序,它们肯定会让阅读和调试代码变得痛苦,但在适当的时候,它们可以少用,并且可以生成更简洁、更高效的代码。在编写一个涉及效率的大型代码库时,它们很难避免。另外,使用write意味着程序无论如何都不是纯逻辑的。write可能只是一个占位符。@liori,顺便说一下,prolog中的if-then和if-then-else构造实际上是使用cut实现的。我之所以提到这一点,是因为你似乎不赞成使用cuts,但你的答案中有if-then-else。使用cuts被认为是不好的。使用cuts确实意味着你的程序不再是一个纯逻辑程序,它们肯定会让阅读和调试代码变得痛苦,但是在适当的时候,它们可以得到更简洁、更高效的代码。在编写一个涉及效率的大型代码库时,它们很难避免。另外,使用write意味着程序无论如何都不是纯逻辑的。write可能只是一个占位符。@liori,顺便说一下,prolog中的if-then和if-then-else构造实际上是使用cut实现的。我之所以提到这一点,是因为你似乎不赞成使用削减,但你的答案中有if-then-else。