2015-11-27 33 views
0

我想约束一个列表的总和,但我的代码在label()失败。参数没有充分实例化名单总和

特等:

:- use_module(library(clpfd)). 

solve(L, Dim) :- 
    length(L, 5), % define 5 diagonals 
    SkipVars is Dim - 2, % to skip variables 
    init_sublists_above_center(L, Dim, SkipVars), 
    init_center(L, 2, Dim), 
    init_sublists_below_center(L, 3, Dim, 1), 
    flatten(L, FlatL), 
    collect_vars(FlatL, _), 
    writeln("list="+L), 
    constraint_sum(L, 38). 

collect_vars([], NewL):- 
    all_different(NewL). 
collect_vars([H|T], NewL) :- 
    H == 0, 
    collect_vars(T, NewL). 
collect_vars([H|T], NewL) :- 
    append(NewL, [H], NewestL), 
    collect_vars(T, NewestL). 

constraint_sum([], _). 
constraint_sum([H|T], Sum) :- 
    writeln(H), 
    label(H), 
    sum_list(H, Sum), 
    constraint_sum(T, Sum). 

init_sublists_above_center([H|T], Dim, SkipVars) :- 
    length(H, Dim), 
    init_zeroes(H, SkipVars), 
    NewSkipVars is SkipVars + 1, 
    NewSkipVars =< Dim, 
    init_sublists_above_center(T, Dim, NewSkipVars). 
init_sublists_above_center(_, _, _). 

init_sublists_below_center(_, _, Dim, Fill) :- 
    End is Dim - 2, 
    Fill == End. 
init_sublists_below_center([H|T], ToSkip, Dim, Fill) :- 
    ToSkip == 0, 
    length(H, Dim), 
    init_zeroes_start(H, Fill), 
    NewFill is Fill + 1, 
    init_sublists_below_center(T, 0, Dim, NewFill). 
init_sublists_below_center([_|T], ToSkip, Dim, Fill) :- 
    NewToSkip is ToSkip - 1, 
    init_sublists_below_center(T, NewToSkip, Dim, Fill). 

init_center(_, ToSkip, _) :- 
    ToSkip == -1. 
init_center([H|_], ToSkip, Dim) :- 
    ToSkip == 0, 
    length(H, Dim), 
    init_center(_, -1, _). 

init_center([_|T], ToSkip, Dim) :- 
    NewToSkip is ToSkip - 1, 
    init_center(T, NewToSkip, Dim). 

init_zeroes([], _). 
init_zeroes([H|T], Fill) :- 
    Fill == 0, 
    H is 0, 
    init_zeroes(T, Fill). 
init_zeroes([_|T], Fill) :- 
    NewFill is Fill - 1, 
    init_zeroes(T, NewFill). 

init_zeroes_start(_, Fill) :- 
    Fill == 0. 
init_zeroes_start([H|T], Fill) :- 
    H is 0, 
    NewFill is Fill - 1, 
    init_zeroes_start(T, NewFill). 

输出:

7 ?- solve(L, 5). 
list= + [[_G15351,_G15407,_G15466,0,0],[_G15525,_G15584,_G15643,_G15702,0],[_G15761,_G15820,_G15879,_G15938,_G15997],[0,_G16056,_G16115,_G16174,_G16233],[0,0,_G16292,_G16351,_G16410]] 
[_G15351,_G15407,_G15466,0,0] 
ERROR: Arguments are not sufficiently instantiated 

任何想法吗?


编辑:

运行调试后:,我认为错误是里面label(),在这一点上:

finite_domain(Var) :- 
     ( fd_get(Var, Dom, _) -> 
      ( domain_infimum(Dom, n(_)), domain_supremum(Dom, n(_)) -> true 
      ; instantiation_error(Var) 
      ) 
     ; integer(Var) -> true 
     ; must_be(integer, Var) 
     ). 
+0

一个想法是运行跟踪然后再次尝试您的查询。键入'trace.'然后执行查询。每个步骤都会详细显示,直到您遇到问题。它将查明问题所在。 – lurker

+0

谢谢潜伏者,从现在开始我会记住这一点! – gsamaras

+1

这是一个方便的工具。有时候,你需要提供一个非常简单的例子,尽管如此,或者你可能整天都在那里跟踪! – lurker

回答

3

使用图形化调试器逐步执行代码:

?- gtrace, solve(L, 5). 

由于您将s ee,label/1与这个错误没有任何关系。

而不是sum_list/2,使用CLP(FD)约束sum/3:它在所有方向工作,并让您看到您的查询的答案。

这就是说,我建议你采取一个巨大的退步,真正考虑你在这里做什么。

例如,为什么混合副作用(write/1)与纯代码?注重对问题的明确说明性描述,并让顶层为您做报告。

另外,如此频繁地需要像逻辑谓词(==)/2这样的异常非常罕见。例如,写:

sublists_below_center(_, _, Dim, End) :- 
    End #= Dim - 2. 

使参数之间的关系完全清晰,而不诉诸超逻辑语言元素。

使用flatten/2几乎总是一个坏主意,通常表明您的数据结构设计存在问题。使用append/2删除一层嵌套。

如果您已经导入CLP(FD)库,为什么还在使用基本算术?整个使用(#=)/2等。

此外,您的谓词名称表明您在思考问题的方式太过于迫切。专注于对问题的解决方案进行纯粹的陈述式描述,而Prolog将为您完成剩下的工作。避免使用命令式的名称。相反,使用描述哪些条件下保存的名称。

+0

s(X):阿门,兄弟! – repeat