参数在列表总和上没有充分实例化

时间:2015-11-27 22:09:43

标签: list prolog instantiation swi-prolog clpfd

我正在尝试约束列表的总和,但我的代码在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)
        ).

1 个答案:

答案 0 :(得分:3)

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

?- gtrace, solve(L, 5).

正如您将看到的,label/1与此错误没有任何关系。

使用CLP(FD)约束sum_list/2代替sum/3:它适用于所有方向,让您查看查询的答案。

话虽这么说,我建议你退后一步,真正考虑一下你在做什么。

例如,为什么要将副作用(write/1)与纯代码混合使用?专注于问题的清晰陈述性描述,让顶层为您做报告。

此外,如此频繁地需要像(==)/2这样的额外逻辑谓词是非常不寻常的。例如,写:

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

使参数之间的关系完全清晰,而不需要使用额外的逻辑语言元素。

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

如果您已经导入CLP(FD)库,为什么还在使用原始算法?始终使用(#=)/2等。

此外,您的谓词名称表明您对问题的看法太过紧迫。专注于对问题解决方案的纯粹陈述性描述,Prolog将为您完成剩下的工作。避免使用命令式名称。相反,使用描述在什么条件下持有的名称。