我正在学习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]
输入数组中,我需要的只是apple
和fruit
。我们通常如何跳过is
字?
我不想为程序硬编码太多东西,而更喜欢一个好的函数编程风格来解决可以帮助我从中学习的问题。
提前谢谢。
答案 0 :(得分: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
规则中引入切换并使用特殊输出处理true / false来改进,但我认为这是我想要的方向,特别是如果您希望能够处理将来不同的语法。
答案 1 :(得分: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.
注意以大写字母开头的符号:这些是变量,而不是 atoms 。