陷入Prolog问题。我知道答案(因为我是先在纸上做的(,但我不知道如何让Prolog给出答案。
问题:
Bill每天晚上都吃零食,吃不同的水果每天晚上吃坚果。从下面的陈述中,确定比尔的目的上周每个工作日晚上吃的零食。
a( 这个星期苹果比芒果吃得晚。
b( 香蕉在本周吃得比杏仁和花生,但本周比梨早。
c( 腰果在本周吃得比香蕉和杏子,但在本周晚些时候比花生。
d( 山核桃在杏仁之后的第二天晚上没有吃。
e( 比尔一天晚上吃了核桃。
注意,问题是大约5个工作日晚上(星期一到星期五(,并提到了5种水果和5种坚果。你的程序应该解决问题并打印出解决方案,这将是一套5个像(星期一,苹果,山核桃(。。。(星期五,芒果,核桃(。
显然,这些不是正确的答案,而只是需要展示的价值观你知道解决方案会是什么样子。
迄今为止的代码:
before_in_week(X, Y, Days) :-
nth1(Xi, Days, X),
nth1(Yi, Days, Y),
Xi < Yi.
print_solve([Head|Tail]) :-
write(Head),
nl,
print_solve(Tail).
solve(A) :-
% all triples
A = [[day1, fruit1, nut1],
[day2, fruit2, nut2],
[day3, fruit3, nut3],
[day4, fruit4, nut4],
[day5, fruit5, nut5]],
Days = [monday, tuesday, wednesday, thursday, friday],
Days = [day1, day2, day3, day4, day5],
Fruits = [apple,banana,pear,mango,apricot],
permutation(Fruits, [fruit1, fruit2, fruit3, fruit4, fruit5]),
Nuts = [almonds,pecans,cashews,peanuts,walnuts],
permutation(Nuts, [nut1, nut2, nut3, nut4, nut5]),
% clue 1 - mango before apple
fruit5 = mango,
member([C1,mango,_], A),
member([C2,apple,_], A), before_in_week(C1,C2,Days),
% clue 2 - banana after almonds and peanuts, but before pear
fruit5 = banana,
member([C1,banana,_], A),
member([C2,pear,_], A), before_in_week(C1,C2,Days),
member([C3,_,almonds], A), before_in_week(C3,C1,Days),
member([C4,_,peanuts], A), before_in_week(C4,C1,Days),
% clue 3 - cashews before banana and apricot, but after peanuts
nut5 = peanuts,
member([C1,_,cashews], A),
member([C2,_,peanuts], A), before_in_week(C1,C2,Days),
member([C3,banana,_], A), before_in_week(C3,C1,Days),
member([C4,apricot,_], A), before_in_week(C4,C1,Days),
% clue 4 - pecans not night after almonds
nut5 = almonds,
% clue 5 - ate walnuts one night
print_solve(A).
首先,确实不需要手动打印任何内容。Prolog的顶级为您做到这一点,如果您还输入查询solve(A).
,
第二,没有解决办法。这正是你真正感兴趣的。有一种非常简单和通用的方法可以缩小失败的根源。简单地概括掉所有的目标,一个接一个。我喜欢通过在前面添加*
来做到这一点,比如:
:-op(950,fy,*(。*_0。求解(A(:-*A=[[day1,fruit1,nut1],[day2,fruit2,nut2],[dday3,fruit3,nut3],[day4,fruit4,nut4],[day 5,fruit5,nut5]],天数=[星期一|_/*[星期二、星期三、星期四、星期五]*/],天数=[第1天|_/*[第2天、第3天、第4天、第5天]*/],*水果=[苹果、香蕉、梨、芒果、杏子],*排列(水果,[水果1,水果2,水果3,水果4,水果5](,*坚果=[杏仁、山核桃、腰果、花生、核桃],*排列(螺母,[nut1,nut2,nut3,nut4,nut5](,%线索1-芒果先于苹果*fruit5\=芒果,*成员([C1,mango,_],A(,*成员([C2,apple,_],A(,before_in_week(C1,C2,Days(,%线索2-香蕉在杏仁和花生之后,但在梨之前*fruit5\=香蕉,*成员([C1,banana,_],A(,*成员([C2,pear,_],A(,before_in_week(C1,C2,Days(,*成员([C3,_,杏仁],A(,before_in_week(C3,C1,Days(,*成员([C4,_,花生],A(,before_in_week(C4,C1,Days(,%线索3——香蕉和杏子之前的腰果,花生之后的腰果*nut5\=花生,*成员([C1,_,腰果],A(,*成员([C2,_,花生],A(,before_in_week(C1,C2,Days(,*成员([C3,banana,_],A(,before_in_week(C3,C1,Days(,*成员([C4,杏,_],A(,before_in_week(C4,C1,Days(,%线索4-山核桃不是杏仁之后的夜晚*坚果5\=杏仁。%线索5-一天晚上吃了核桃
在这个程序切片中,这是对你原来程序的概括,它归结为无法成功
Days = [monday|_], Days = [day1|_]
你必须改变一些东西。day1
是一个常数,它应该是一个变量。
稍后,用dif(X, const)
替换所有X = const
。
最大的问题是使用原子(fruit4
(,但应该使用变量(Fruit4
(。注意开头的大写字母。
此外,你正在做一个你不需要的排列。Prolog通过回溯来完成所有需要的排列。这就是Prolog成为如此有趣的语言的原因。
试试这个代码:
?- solve(A),print_solve(A).
solve(A) :-
A = [[monday,_,_],[tuesday,_,_],[wednesday,_,_],[thursday,_,_],[friday,_,_]],
%clue 1 - mango before apple
before([_,mango,_],[_,apple,_],A),
% clue 2 - banana after almonds and peanuts, but before pear
before([_,_,almonds],[_,banana,_],A),
before([_,_,peanuts],[_,banana,_],A),
before([_,banana,_],[_,pear,_],A),
% clue 3 - cashews before banana and apricot, but after peanuts
before([_,_,cashews],[_,banana,_],A),
before([_,_,cashews],[_,apricot,_],A),
before([_,_,peanuts],[_,_,cashews],A),
% clue 4 - pecans not night after almonds
append(H,[[_,_,almonds],[_,_,_]|T],A),
(member([_,_,pecans],H);member([_,_,pecans],T)),
% clue 5 - ate walnuts one night
member([_,_,walnuts],A),
true.
print_solve([]).
print_solve([Head|Tail]) :-
write(Head),
nl,
print_solve(Tail).
before(X,Y,Days) :-
append(A,B,Days),
member(X,A),
member(Y,B).
这给了我:
[星期一,芒果,花生][星期二,苹果,腰果][星期三,杏子,杏仁][星期四,香蕉,核桃][星期五,梨,山核桃]是的
这个谜题可以通过Prolog的一个主要工具轻松解决:生成和测试。关键是在域变量(约束(上建模表达式,以便检查它们是否满足要求。
snacks(Week) :-
% model the problem with domain variables,
% make the symbolic associations explicit
% this is the 'generation phase'
Nuts = [
almonds:Almonds,
cashews:Cashews,
pecans:Pecans,
peanuts:Peanuts,
walnuts:_Walnuts
],
Fruits = [
apple:Apple,
banana:Banana,
pear:Pear,
mango:Mango,
apricot:Apricot
],
% since we are going to use plain arithmetic, assign numbers before attempt to evaluate constraints
assign_days(Nuts),
assign_days(Fruits),
% now the 'application symbols' are bound to integers, then we can
% code actual constraint expressions in a simple way...
% this is the 'test phase'
% a) The apple was eaten later in the week than the mango.
Apple>Mango,
% b) The banana was eaten later in the week than both the almonds and peanuts,
% but earlier in the week than the pear.
Banana>Almonds,Banana>Peanuts,Banana<Pear,
% c) The cashews were eaten earlier in the week than both the banana and the apricot,
% but later in the week than the peanuts.
Cashews<Banana,Cashews<Apricot,Cashews>Peanuts,
% d) The pecans were not eaten the evening after the almonds.
Pecans==Almonds+1,
% e) Bill ate walnuts one night.
% no constraints, just existance
% when we get here, domain variables satisfy the constraints
% just format the workspace in easy to read list
findall((Day,Fruit,Nut),(
nth1(NDay,['Monday','Tuesday','Wednesday','Thursday','Friday'],Day),
memberchk(Fruit:NDay,Fruits),
memberchk(Nut:NDay,Nuts)
),Week).
assign_days(Snacks) :-
numlist(1,5,Nums),
permutation(Nums,Perm),
maplist([Day,_:Day]>>true,Perm,Snacks).