List 序言:选择在列表递归期间不插入元素
我做了一个谓词,它将2个list作为参数,并返回一个与“recipesub”的乘积连接的列表,但是我需要做第三个规则,如果手头的产品是空列表,则禁止插入该产品 因此,第一个列表可以如下所示:List 序言:选择在列表递归期间不插入元素,list,recursion,prolog,List,Recursion,Prolog,我做了一个谓词,它将2个list作为参数,并返回一个与“recipesub”的乘积连接的列表,但是我需要做第三个规则,如果手头的产品是空列表,则禁止插入该产品 因此,第一个列表可以如下所示: recipe([ingredient(rice,4),ingredient(salt,3),ingredient(water,5)]). ingredients([ingredient(rice,3),ingredient(salt,4),ingredient(water,4), need_to_buy
recipe([ingredient(rice,4),ingredient(salt,3),ingredient(water,5)]).
ingredients([ingredient(rice,3),ingredient(salt,4),ingredient(water,4),
need_to_buy([], _, []).
% case 1: we don't have the ingredient at all
need_to_buy([ingredient(Type, AmountNeeded) | Ingredients],
OnHand,
[ingredient(Type, AmountNeeded)|Needed]) :-
\+ memberchk(ingredient(Type, _), OnHand),
need_to_buy(Ingredients, OnHand, Needed).
% case 2: we have it, but not enough
need_to_buy([ingredient(Type, AmountNeeded) | Ingredients],
OnHand,
[ingredient(Type, AmountToBuy)|RestNeeded]) :-
memberchk(ingredient(Type, AmountOnHand), OnHand),
AmountNeeded > AmountOnHand,
AmountToBuy is AmountNeeded - AmountOnHand,
need_to_buy(Ingredients, OnHand, RestNeeded).
% case 3: we have enough
need_to_buy([ingredient(Type, AmountNeeded) | Ingredients],
OnHand,
RestNeeded) :-
memberchk(ingredient(Type, AmountOnHand), OnHand),
AmountNeeded =< AmountOnHand,
need_to_buy(Ingredients, OnHand, RestNeeded).
第二个是这样的:
recipe([ingredient(rice,4),ingredient(salt,3),ingredient(water,5)]).
ingredients([ingredient(rice,3),ingredient(salt,4),ingredient(water,4),
need_to_buy([], _, []).
% case 1: we don't have the ingredient at all
need_to_buy([ingredient(Type, AmountNeeded) | Ingredients],
OnHand,
[ingredient(Type, AmountNeeded)|Needed]) :-
\+ memberchk(ingredient(Type, _), OnHand),
need_to_buy(Ingredients, OnHand, Needed).
% case 2: we have it, but not enough
need_to_buy([ingredient(Type, AmountNeeded) | Ingredients],
OnHand,
[ingredient(Type, AmountToBuy)|RestNeeded]) :-
memberchk(ingredient(Type, AmountOnHand), OnHand),
AmountNeeded > AmountOnHand,
AmountToBuy is AmountNeeded - AmountOnHand,
need_to_buy(Ingredients, OnHand, RestNeeded).
% case 3: we have enough
need_to_buy([ingredient(Type, AmountNeeded) | Ingredients],
OnHand,
RestNeeded) :-
memberchk(ingredient(Type, AmountOnHand), OnHand),
AmountNeeded =< AmountOnHand,
need_to_buy(Ingredients, OnHand, RestNeeded).
当它返回时:List=[配料(大米,1),[],配料(水,1)]
我希望它返回:List=[配料(大米,1),配料(水,1)]
下面是我在解决方案方面取得的进展
/*need_to_buy([H|Hs],[X|Xs],List):-
H = ingredient(Type,Amount),
recipesub(Type,Amount,[X|Xs],Difference),
Difference = [],
need_to_buy(Hs,[X|Xs],List).*/
这是支持谓词,recipesub
recipesub(Type,Amount,[],Difference):-
Difference = ingredient(Type,Amount).
recipesub(Type,Amount,[Z|_],Difference):-
Z = ingredient(Type,Stock),
Amount>Stock,
NewAmount is Amount-Stock,
Difference = ingredient(Type,NewAmount).
recipesub(Type,Amount,[Z|_],Difference):-
Z = ingredient(Type, Stock),
Stock >= Amount,
Difference = [].
recipesub(Type,Amount,[Z|Zs],Difference):-
Z = ingredient(WrongType,_),
WrongType \= Type,
recipesub(Type,Amount,Zs,Difference).
我通常不会做很多嵌套条件,但这次“感觉不错”,这就是我找到的解决方案:
need_to_buy([], _, []).
need_to_buy([ingredient(Type, AmountNeeded)|Ingredients], OnHand, Needed) :-
% Do we have any on-hand?
member(ingredient(Type, AmountOnHand), OnHand) ->
% If the amount on-hand is greater than the amount needed,
% just hand off the rest
(AmountOnHand >= AmountNeeded ->
need_to_buy(Ingredients, OnHand, Needed)
% otherwise, calculate the amount needed and recur
; (AmountToBuy is AmountNeeded - AmountOnHand,
need_to_buy(Ingredients, OnHand, RestNeeded),
Needed = [ingredient(Type, AmountToBuy)|RestNeeded]))
% If we have none on-hand, we can just use the amount needed
% to form the request, and recur
; need_to_buy(Ingredients, OnHand, RestNeeded),
Needed = [ingredient(Type, AmountNeeded)|RestNeeded].
否则我认为你会有很多相当低效的测试和重新测试。我在代码中看到的主要错误是第二个参数的模式匹配。依靠member/2
或memberchk/2
可以更轻松地从手头的东西中找到合适的成分
如果我用一堆子句来代替,它可能会是这样的:
recipe([ingredient(rice,4),ingredient(salt,3),ingredient(water,5)]).
ingredients([ingredient(rice,3),ingredient(salt,4),ingredient(water,4),
need_to_buy([], _, []).
% case 1: we don't have the ingredient at all
need_to_buy([ingredient(Type, AmountNeeded) | Ingredients],
OnHand,
[ingredient(Type, AmountNeeded)|Needed]) :-
\+ memberchk(ingredient(Type, _), OnHand),
need_to_buy(Ingredients, OnHand, Needed).
% case 2: we have it, but not enough
need_to_buy([ingredient(Type, AmountNeeded) | Ingredients],
OnHand,
[ingredient(Type, AmountToBuy)|RestNeeded]) :-
memberchk(ingredient(Type, AmountOnHand), OnHand),
AmountNeeded > AmountOnHand,
AmountToBuy is AmountNeeded - AmountOnHand,
need_to_buy(Ingredients, OnHand, RestNeeded).
% case 3: we have enough
need_to_buy([ingredient(Type, AmountNeeded) | Ingredients],
OnHand,
RestNeeded) :-
memberchk(ingredient(Type, AmountOnHand), OnHand),
AmountNeeded =< AmountOnHand,
need_to_buy(Ingredients, OnHand, RestNeeded).
需要购买([],[])。
%案例1:我们根本没有原料
需要购买([配料(类型、所需数量)|配料],
现在,
[成分(类型、所需数量)|所需]:-
\+memberchk(成分(类型),现有),
需要购买(原料、现货、需要)。
%案例2:我们有,但还不够
需要购买([配料(类型、所需数量)|配料],
现在,
[成分(类型、购买量)|需要时]:-
memberchk(成分(类型、数量和数量),现有),
需要的数量>需要的数量,
AmountToBuy是所需数量-AmountOnHand,
需要购买(原料、现货、需要时)。
%案例3:我们已经足够了
需要购买([配料(类型、所需数量)|配料],
现在,
(需要时):-
memberchk(成分(类型、数量和数量),现有),
AmountNeeded=
这在堆栈上留下了一个选择点,通常看起来像是为了我的口味重新测试相同的条件和遍历。但是,如果你觉得它更好的话,它也应该起同样的作用。我最终解决了这个问题,将第二条“需要购买”规则分为两条,一条处理差异是空列表的情况,另一条处理差异不是空列表的情况 一开始我遇到了一些麻烦,但事实证明规则的“方向”给我带来了麻烦,所以我不得不将处理差异\=[]情况的规则置于差异=[]的规则之上。 现在看起来是这样的:
need_to_buy([],_,List):- List = [].
need_to_buy([H|Hs],[X|Xs],[Difference|List]):-
H = ingredient(Type,Amount),
recipesub(Type,Amount,[X|Xs],Difference),
Difference \= [],
need_to_buy(Hs,[X|Xs],List).
need_to_buy([H|Hs],[X|Xs],List):-
H = ingredient(Type,Amount),
recipesub(Type,Amount,[X|Xs],Difference),
Difference = [],
need_to_buy(Hs,[X|Xs],List).
请这是什么?
recipesub/4
?recipesub是一个谓词,它递归地将第一个列表的头与第二个列表中的每个元素进行比较,如果“H”中的变量“Amount”小于X中的“Amount”,则返回差=成分(type,requiredAmount),但如果X中的可变金额大于H中的可变金额,则返回一个空列表。好的,对不起,我现在已尽我所能进行了更正。您可以在需要购买
谓词中检查[]
(从配方返回
),或者你可以让recipesub
失败,而不是提供[]
作为解决方案,当recipesub
失败时,让need\u\u购买
“做正确的事情”。谢谢你的回复,但当我看到你的代码时,我已经想出了一个解决方案。