我正试图解决荷兰国旗问题的解决方案。基本上,给定一个列表,我想按照Red-White-Blue的顺序对它们进行排序。红色,白色和蓝色由它们的谓词定义(即红色(x),白色(x)等) 目前,我有以下代码:
red(1).
white(2).
blue(3).
dutch(Xs,Ys):-
getRed(Xs,[], Red), getWhite(Xs,[],White), getBlue(Xs,[],Blue),
append([], Red, Y1), append(Y1, White, Y2), append(Y2, Blue, Ys).
getRed([],Rs,Rs).
getRed([X|Rest], Acc, Rs) :- red(X), getRed(Rest, [X,Acc] , Rs).
getRed([X|Rest], Acc, Rs) :- getRed(Rest, Acc, Rs).
getWhite([],Rs,Rs).
getWhite([X|Rest], Acc, Rs) :- white(X), getWhite(Rest, [X,Acc], Rs).
getWhite([X|Rest], Acc, Rs) :- getWhite(Rest, Acc, Rs).
getBlue([],Rs,Rs).
getBlue([X|Rest], Acc, Rs) :- blue(X), getBlue(Rest, [X,Acc], Rs).
getBlue([X|Rest], Acc, Rs) :- getBlue(Rest, Acc, Rs).
我的输出如下:
?- dutch([1,2,3],R).
R = [1, [], 2, [], 3, []]
R = [1, [], 2, []]
R = [1, [], 3, []]
R = [1, []]
R = [2, [], 3, []]
R = [3, []]
R = []
我想要的是它看起来像这样:
R = [1, 2, 3]
我已经尝试了几种方法来强制输出到我想要的,但是无法靠近任何地方。
编辑:看起来我可以通过使用蛮力解决方案来解决所有可能的集合并评估集合是否处于“荷兰国旗”顺序。有没有更好的解决方案?
答案 0 :(得分:1)
我想在现有解决方案中添加纯,关系解决方案。
理想情况下,您可以在所有方向中使用Prolog谓词,现在我将展示一个允许您执行此操作的实现:您不仅可以对实例化列表进行排序根据您的标准,不,您还可以生成解决方案和完整部分实例化的解决方案。
为此,我使用library(reif)
中的元谓词 if_/3
。
我从谓词的具体化版本开始,也可以自由地使用更有说服力的名称red
,white
和blue
来表示颜色:
red(R, T) :- =(R, red, T). white(W, T) :- =(W, white, T). blue(B, T) :- =(B, blue, T).
注意我使用(=)/3
,library(reif)
免费提供。
接下来,纯粹为方便起见,我使用 dcg 表示法来描述感兴趣的子序列:
reds([]) --> []. reds(Rs) --> [R], { if_(red(R), Rs = [R|Rest], Rs = Rest) }, reds(Rest). whites([]) --> []. whites(Ws) --> [W], { if_(white(W), Ws = [W|Rest], Ws = Rest) }, whites(Rest). blues([]) --> []. blues(Bs) --> [B], { if_(blue(B), Bs = [B|Rest], Bs = Rest) }, blues(Rest).
我让这个更简洁,这是一个简单的练习。
通过这些构建模块,我们可以表达整体解决方案:
dutch(Colors, Ds) :- phrase(reds(Rs), Colors), phrase(whites(Ws), Colors), phrase(blues(Bs), Colors), phrase((Rs,Ws,Bs), Ds).
当然,这适用于简单的实例化案例,如:
?- dutch([red,white,blue], Ds). Ds = [red, white, blue] ; false.
现在重点:此也适用于最常见的情况,其中所有参数都是变量:
?- length(Cs, _), dutch(Cs, Ds). Cs = Ds, Ds = [] ; Cs = Ds, Ds = [red] ; Cs = Ds, Ds = [white] ; Cs = Ds, Ds = [blue] ; Cs = [_G1322], Ds = [], dif(_G1322, blue), dif(_G1322, white), dif(_G1322, red) ; Cs = Ds, Ds = [red, red] ; Cs = Ds, Ds = [red, white] ; Cs = Ds, Ds = [red, blue] ; Cs = [red, _G1340], Ds = [red], dif(_G1340, blue), dif(_G1340, white), dif(_G1340, red) .
通过添加更多目标,我们可以专门化此查询,以观察现在生成的具体解决方案:
?- length(Cs, _), Cs = [_,_,_|_], dutch(Cs, Ds), ground(Cs). Cs = Ds, Ds = [red, red, red] ; Cs = Ds, Ds = [red, red, white] ; Cs = Ds, Ds = [red, red, blue] ; Cs = [red, white, red], Ds = [red, red, white] ; Cs = [red, blue, red], Ds = [red, red, blue] .
将此与other answer进行比较,无法用于公平地枚举解决方案:
?- length(Xs, _), Xs = [_,_,_|_], dutch(Xs, Ys). Xs = Ys, Ys = [1, 1, 1] ; Xs = Ys, Ys = [1, 1, 1, 1] ; Xs = Ys, Ys = [1, 1, 1, 1, 1] ; Xs = Ys, Ys = [1, 1, 1, 1, 1, 1] ; Xs = Ys, Ys = [1, 1, 1, 1, 1, 1, 1] .
因此,通过保留logical-purity,我们获得了一个更通用的逻辑程序,我们可以在所有方向上使用它。
诚然,你没有要求这种普遍性。但是,当我们在这时,为什么要放弃?
答案 1 :(得分:0)
我在您的代码中看到两个错误:
1)您的终端条款getRed([],Rs,Rs)
,getWhite([],Rs,Rs)
,getBlue([],Rs,Rs)
接受空列表作为结果列表(当Rs
等于[]
时) ;我建议把它们重写为
getRed([],Rs,Rs) :- Rs \= [].
getWhite([],Rs,Rs) :- Rs \= [].
getBlue([],Rs,Rs) :- Rs \= [].
2)在接受条款中(当X
是搜索的颜色时),当你应该使用管道([X,Acc]
时,用逗号将它添加到累加器中;应该是{{1} }});我建议将它们重写为
[X|Acc]
关闭主题:没有理由将getRed([X|Rest], Acc, Rs) :- red(X), getRed(Rest, [X|Acc], Rs).
getWhite([X|Rest], Acc, Rs) :- white(X), getWhite(Rest, [X|Acc] , Rs).
getBlue([X|Rest], Acc, Rs) :- blue(X), getBlue(Rest, [X|Acc], Rs).
附加到空列表中;结果列表(Red
)本身是Y1
;我建议简化
Red
如下
append([], Red, Y1), append(Y1, White, Y2), append(Y2, Blue, Ys)
---编辑---
不确定你究竟想要什么,但我怀疑第三版条款中的第三个错误:append(Red, White, Mid), append(Mid, Blue, Ys)
没有积累。
我认为您应该添加一项检查,以确保X
不是搜索到的颜色;我建议将它们改写如下
X
---编辑2 ---
我不会在getRed([X|Rest], Acc, Rs) :- \+ red(X), getRed(Rest, Acc, Rs).
getWhite([X|Rest], Acc, Rs) :- \+ white(X), getWhite(Rest, Acc, Rs).
getBlue([X|Rest], Acc, Rs) :- \+ blue(X), getBlue(Rest, Acc, Rs).
,getRed/3
和getWhite/3
条款中看到累加器的需要。
我建议只有2个参数的版本
getBlue/3