【问题标题】:Prolog recursive predicate returns to initial state after endingProlog递归谓词结束后返回初始状态
【发布时间】:2021-04-06 12:08:04
【问题描述】:

我是 Prolog 的新手,在理解我的代码有什么问题时遇到了一些麻烦。

我正在尝试做一个食物推荐者。基本上,用户输入他们是否想要早餐、午餐或甜点以及他们的口味列表。然后程序计算他们的口味与每种食物的特征之间的匹配次数,并返回匹配最多的食物。

我正在使用递归遍历食物列表,一切都按预期工作,直到它到达带有空食物列表的末尾,然后再次开始填充它,回到问题的初始状态。我不明白为什么程序会这样做,我找不到解决方案。

recommend(breakfast, Tastes, Result) :-
    findall(Breakfast, breakfast(Breakfast), Breakfasts),
    getBestMatch(Breakfasts, Tastes, Result, -1).

recommend(lunch, Tastes, Result) :-
    findall(Lunch, lunch(Lunch), Lunches),
    getBestMatch(Lunches, Tastes, Result, -1).

recommend(dessert, Tastes, Result) :-
    findall(Dessert, dessert(Dessert), Desserts),
    getBestMatch(Desserts, Tastes, Result, -1).


% Recursive predicate. Goes through the list of food and calls the matches predicate to count the
% matches and compares it to the current best match. When the food list is empty, it should stop. 
% Result should be the name of the best matching food. I think here's where the error is. 

getBestMatch([], _, _, _).
getBestMatch([H|T], Tastes, Result, BestMatch) :-
    matches(H, Tastes, Matches),
    Matches > BestMatch
    -> getBestMatch(T, Tastes, H, Matches)
    ; getBestMatch(T, Tastes, Result, BestMatch).


% Counts the number of matches between the food's characteristics and the tastes.

matches(Food, Tastes, Matches) :-
    characteristics(Food, Characteristics),
    intersection(Tastes, Characteristics, MatchList),
    length(MatchList, Matches).

% These are some examples of how I have declared the food and its characteristics

lunch(lasagna).
lunch(pizza).
dessert(cake).

characteristics(lasagna, [warm, salty, pasta, italian, meat]).
characteristics(pizza, [warm, salty, cheese, italian]).
characteristics(cake, [cold, sweet, vegetarian]).

这是跟踪的片段。

   Call: (12) getBestMatch([pizza], [italian, cheese], lasagna, 1) ? creep
   Call: (13) matches(pizza, [italian, cheese], _4220) ? creep
   Call: (14) characteristics(pizza, _4262) ? creep
   Exit: (14) characteristics(pizza, [warm, salty, cheese, italian]) ? creep
   Call: (14) lists:intersection([italian, cheese], [warm, salty, cheese, italian], _4376) ? creep
   Exit: (14) lists:intersection([italian, cheese], [warm, salty, cheese, italian], [italian, cheese]) ? creep
   Call: (14) length([italian, cheese], _4474) ? creep
   Exit: (14) length([italian, cheese], 2) ? creep
   Exit: (13) matches(pizza, [italian, cheese], 2) ? creep
   Call: (13) 2>1 ? creep
   Exit: (13) 2>1 ? creep
   Call: (13) getBestMatch([], [italian, cheese], pizza, 2) ? creep
   Exit: (13) getBestMatch([], [italian, cheese], pizza, 2) ? creep
   Exit: (12) getBestMatch([pizza], [italian, cheese], lasagna, 1) ? creep
   Exit: (11) getBestMatch([lasagna, pizza], [italian, cheese], _2882, -1) ? creep
   Exit: (10) recommend(lunch, [italian, cheese], _2882) ? creep
true.

我尝试过查看类似的问题,但没有一个对我有用。

PS:对不起,如果这个问题或代码示例太大,这是我在这里的第一个问题,我无法弄清楚如何进一步简化它。

【问题讨论】:

  • listing(getBestMatch)查看问题
  • 否则,一个可重现的案例会有所帮助。

标签: list recursion prolog


【解决方案1】:

您的 getBestMatch/4 谓词中有些东西混淆了。让我们来看看属性的角色:

  1. 属性[H|T] 似乎是可供选择的菜肴列表(输入)。
  2. 属性Tastes 似乎是首选属性列表(输入)。
  3. 属性Result 似乎是列表(输出)中最喜欢的菜。
  4. 属性BestMatch 似乎是最佳匹配值(输入?最好是输出)。

你在这个子句中有一个 if-then-else,它读作伪代码:

if matches(H, Tastes, Matches) and if Matches > BestMatch
then getBestMatch(T, Tastes, H, Matches)
else getBestMatch(T, Tastes, Result, BestMatch)

这里有一些问题,比如将属性值相互连接。让我们尝试解决它。最初何时停止:如果您的 List 为空,则返回 -1BestMatch

getBestMatch([], _, _, -1).

现在在做任何事情之前,您需要知道尾部列表 T 中的 BestMatch 值是什么,以便将您当前的元素 H 与它进行比较:

getBestMatch([H|T], Tastes, Result, BestMatch) :-
    getBestMatch(T, Tastes, TmpRes, TmpBest),

假设尚未编程的代码有效,您现在知道来自TmpRes 的推荐,评分为TmpBest。现在你需要知道你当前菜品的分数H

    matches(H, Tastes, Matches),

然后是 if-then-else 用于将正确的结果通过隧道传送到“输出”

    (   Matches > TmpBest
    ->  Result = H,
        BestMatch = Matches
    ;   Result = TmpRes,
        BestMatch = TmpBest
    ).

或者作为getBestMatch/4的完整代码:

getBestMatch([], _, _, -1).
getBestMatch([H|T], Tastes, Result, BestMatch) :-
    getBestMatch(T, Tastes, TmpRes, TmpBest),
    matches(H, Tastes, Matches),
    (   Matches > TmpBest
    ->  Result = H,
        BestMatch = Matches
    ;   Result = TmpRes,
        BestMatch = TmpBest
    ).

好的,我们来测试一下:

?- getBestMatch([pizza], [italian, cheese], L, _).
L = pizza.

?- getBestMatch([pizza,lasagna,cake], [italian], L, _).
L = lasagna.

乍一看似乎有效,但问题是列表中的菜品顺序对菜品有偏好(右边更多是严格偏好的)。如果愿意,也可以修复此问题。

要使这个更改的谓词起作用,您需要更改调用

getBestMatch(Breakfasts, Tastes, Result, -1).

getBestMatch(Breakfasts, Tastes, Result, _).

下划线_ 表示这是一个您对其值不感兴趣的变量。

测试recommend/3

?- recommend(lunch, [warm, meat],L).
L = lasagna.

?- recommend(lunch, [warm, cheese],L).
L = pizza.

?- recommend(lunch, [sweet], L).
L = pizza.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-09
    • 1970-01-01
    • 1970-01-01
    • 2011-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多