首页 > 解决方案 > 求和比较规则失败

问题描述

我的问题是关于在 Prolog 中表示列表的问题。
我有两个知识库,我需要按人显示他们可以购买的产品和价格,而不是按人显示所有产品。钱的条件是每个人都可以花的。

%. The knowledge base of elements and their prices.

product (cookies, 3).
product (coca_cola, 2).
product (potatoes, 2).
product (tomatoes, 4).
product (meat, 6).
product (fish, 4).

%. The knowledge base of people and their spending money.

person (aria, 10).
person (Robert, 16).
person (Jim, 20).

% The rule I need to show name's person and the products and it's price, that each person 
% can buy with the money they have.
% Once I get this, I need her to propose me products at random, 
% until I reach the money of each person.


show_products(X,Y):-product(X,Y).
show_persons(X,Y):-person(X,Y).

% With this I show all persons with all products price.
show_product_spend(X,Y,Z):-person(X,_),product(Y,Z).

% Apend is not sufficiently instantiated in that rule...
show_product_2(X,Y,Z):-person(X,Money), product(Y,Z), Apend is Z + Apend, Apend < Money.

% But if it is instantiated. Add is Z+Add, it do not add, compare.
% and Add < Money return false.
instantiate(0).
show_product_3(X,Y,Z):-person(X,Money), product(Y,Z), instantiate(Add), Add is Z + Add, Add < Money.

我已经搜索了几天,但没有找到解决方案。我很绝望。
我了解到列表有点帮助,但是列表的问题是相似的。
用变量控制产品的累计价格不超过每个人的钱的限制,从而不会继续展示更多的产品。
Prolog 变量不能修改它的数据,这就是问题所在。在我的问题中找到了这个可能的解决方案:

allowed_input (1). % your
allowed_input (2). % knowledge
allowed_input (3). %        base

restricted_sum (A, B, C): -
    allowed_input (A),% test user input's
    allowed_input (B),% validity
    C is A + B. % test the result

但这对我不起作用,这显示了结果的组合。

我希望有人能帮助我。谢谢!

标签: prolog

解决方案


欢迎来到 SO。请注意,变量以大写字母开头,所以事实

person (Robert, 16).
person (Jim, 20).

不要陈述任何关于名为 Robert 或 Jim 的人的信息,但以下内容会:

person(robert, 16).
person(jim, 20).

此外,我的 SWI 序言不允许谓词名称和括号之间有空格。

你真的应该了解列表,因为这些会解决你的问题。当您看到这些括号时,您就知道这是一个列表:[...]. 列表通常通过将其分成第一个元素H(头元素)和一个其余列表T(尾)来使用,写为[H|T],例如:

?- L=[a,b,c], L=[H|C].
L = [a, b, c],
H = a,
C = [b, c].

好吧,如果我理解正确的话,你希望每个人都能买到他或她能买到的所有食物。这看起来像这样:

spend_money_on_products(P,L)

whereP是一个人,L是一个人能负担得起的食物及其价格的清单。
我将把我的代码放在这里并逐步解释。

getproducts(M,In,[(Prod,Amount)|Out]):-
    product(Prod,Amount), % guess product
    \+ member(Prod,In), % no duplicates
    Amount =< M, % enough money
    Mnew is M - Amount, % subtract
    getproducts(Mnew,[Prod|In],Out).
getproducts(_, _, []).

spend_money_on_products(P,L):-
    person(P,M),
    getproducts(M,[],L).

M所以首先我们需要知道一个人有多少钱Pperson(P,M). 简单的。现在我们对这个人P不再感兴趣,可以专注于金钱M。现在我们可以从一个空篮子(空 List )开始询问L我们可以购买的物品:M[]

getproducts(M,[],L)

现在我们需要定义如何处理getproducts/3. 这个谓词有 3 个参数:剩下的钱,一个代表购物篮的列表和一个代表已装满价格的购物篮的列表。首先,我们猜测Prod价格为Amount( product(Prod,Amount)) 的产品。然后我们检查这个项目是否已经在篮子里(\+ member(Prod,In)\+/2可以读作没有)。如果您对列表中的重复项不感兴趣,可以删除此行。

接下来是检查是否有足够的钱购买该物品(Amount =< M)。如果是这样,您可以减去此金额 ( Mnew is M - Amount)。现在您有不同数量的钱 ( Mnew),您应该将产品添加到您的购物篮中,将其作为列表 ( [Prod|In]) 的头部元素。现在你可以用新的金额和新的篮子再次问这个问题getproducts(Mnew,[Prod|In],Out)

一旦没有可找到的项目,您将返回一个空列表 ( getproducts(_, _, []).)。动作的顺序由它们的位置决定,所以它首先尝试按照第一条规则匹配每个产品,如果没有找到任何产品,它只会说退货篮是空的。

我们忘记了一件事:退货篮还没有装满。这是通过在匹配时“收集”所有购买的物品来完成的(第一行)getproducts(M,In,[(Prod,Amount)|Out]):。一旦你成功找到了一个Prod价格的项目Amount,你把它作为你的购物篮中的头元素。

让我们测试一下:

?- spend_money_on_products(aria,L).
L = [(cookies,3), (coca_cola,2), (potatoes,2)] ;
L = [(cookies,3), (coca_cola,2), (tomatoes,4)] ;
L = [(cookies,3), (coca_cola,2), (fish,4)] ;
L = [(cookies,3), (coca_cola,2)] ;
L = [(cookies,3), (potatoes,2), (coca_cola,2)] ;
...

看起来挺好的。请注意,每一行都是不同的购物篮。它们用分号隔开;。空篮子也可以。


推荐阅读