1

我正在学习 Prolog 的想法,这是我想要练习的:

我想编写一个可以像这样工作的 Prolog 程序:

?- input([apple,is,fruit]).
?- input([chicken,is,meat]).
?- input([Is,apple,meat]).
No, it is a fruit
?- input[(Is,chicken,meat])
Yes.

当我试图实现这个程序时,我遇到了一些问题:

(1) 我使用这段代码试图读取输入并区分问题和断言,但它失败了:

input([]).
input([X|R]) :- X is 'Is', write('test code read question'); write("test code read assertion").

(2)我仍然对如何从输入消息中过滤出有用的信息感到困惑。例如,在[Apple,is,fruit]输入数组中,我只需要applefruit。我们平时是怎么跳is字的呢?

我不想在程序中硬编码太多东西,而是更喜欢一种好的函数式编程风格来解决可以帮助我从中学习的问题。

先感谢您。

4

2 回答 2

6

仅仅因为我喜欢它们,我会倾向于使用明确的从句语法(DCG)。然后你可以很容易地做出陈述并解析它们:

word(Word) --> [Word].
statement(Statement) --> 
    word(Thing), [is], word(Category), 
    { Statement =.. [Category, Thing] }.

DCG 的诀窍是您的语法正在转换为差异列表表示。括号中的部分是普通的 Prolog 代码;它周围的部分被解释为列表的文字部分或其他语法规则。所以 [Word] 匹配一个原子。我们实际上可以这样写规则:

statement(Statement) -->
    [Thing, is, Category],
    { Statement =.. [Category, Thing] }.

它会产生相同的效果,也许更具可读性,但我喜欢迂腐。特别注意使用=..,它将列表转换为事实,反之亦然(因此[fruit, apple]变为fruit(apple))。

使用 DCG 进行解析非常简单:使用phrase/2

?- phrase(statement(X), [apple,is,fruit]).
X = fruit(apple).

然后您可以使用asserta将这些子句插入到动态存储中:

input(Text) :- 
    phrase(statement(Statement), Text),
    asserta(Statement).

例如:

?- input([apple,is,fruit]).
true.

?- fruit(X).
X = apple.

现在您可以编写另一个子句来解析查询:

query(Query) --> 
    ['Is'], word(Word), word(Category), 
    { Query =.. [Category, Word] }.

看起来非常相似!同样,如果您愿意,可以使用以下语法:

query(Query) -->
    ['Is', Word, Category],
    { Query =.. [Category, Word] }.

现在您可能想要编写一个子句将两个语法规则组合成一个“句子”规则:

sentence(statement(S)) --> statement(S).
sentence(query(Q))     --> query(Q).

试试看:

?- phrase(sentence(X), ['Is', apple, fruit]).
X = query(fruit(apple)).

?- phrase(sentence(X), [apple, 'is', fruit]).
X = statement(fruit(apple)) ;

您现在看到,我们不仅得到了解析的事实,而且还得到了一个包装器,它告诉我们它是一个语句还是一个查询。我们现在可以用 this 而不是语句和查询来解析,并input像这样重写:

input(Text) :-
    phrase(sentence(S), Text), perform(S).

我添加了一个辅助来处理这项工作:

perform(statement(S)) :- asserta(S).
perform(query(Q))     :- Q.

当您添加更多语法抽象时,这将很方便:每个perform子句处理不同的“句子”类型,因此您在上面进行解析并处理下面的工作。现在,我们或多或少地拥有了您想要的东西:

?- input([apple,is,fruit]).
true ;
false.

?- input(['Is',apple,fruit]).
true.

?- input(['Is',banana,fruit]).
false.

您可以通过在sentence规则中引入削减并使用特殊输出处理真/假来改进事情,但我认为这是我想要进入的方向,特别是如果您希望将来能够处理不同的语法。

于 2012-10-04T19:23:02.943 回答
1

您没有使用 Prolog 语法。您所描述的可以通过这种方式实现(未经测试的代码):

:- dynamic facts/1.

input(L) :-
  (  L == [is|_]
  -> (  facts(L)
     -> true
     ;  get_kind(L, K), format('no, it is ~w~n', [K])
     )
  ;  assert(facts(L))  % should check duplicates?
  ).

get_kind([is, Object, _], Kind) :-
  facts([Object, is, Kind]) -> true ; Kind = unknow.

注意以大写开头的符号:这些是变量,而不是原子

于 2012-10-04T19:08:04.170 回答