在列表成员实例化时不传播约束



我正在构建日期和时间的解析器和生成器。在普通的编程语言中,这些将被单独编写。在Prolog+CLP(FD)中,我可以写一个谓词,同时:-)

在我的用例中,解析一些数字并将其转换为整数,或者根据给定的整数生成一些数字,通常是有意义的。

我的问题是clpfd:run_propagator/2在实例化单个数字时没有被调用,尽管我使用clpfd:init_propagator/2声明。有办法做到这一点,还是我在我的clpfd_digits/2的定义一个错误?

在sw - prolog中实现的代码:

:- use_module(library(apply)).
:- use_module(library(clpfd)).
:- multifile(clpfd:run_propagator/2).
day(D) --> {clpfd_digits(D, [D1,D2])}, digit(D1), digit(D2).
digit(D) --> [C], {code_type(C, digit(D))}.
clpfd_digits(N, Ds):-
  clpfd:make_propagator(clpfd_digits(N, Ds), Prop),
  clpfd:init_propagator(N, Prop),
  clpfd:init_propagator(Ds, Prop),
  forall(
    member(D, Ds),
    clpfd:init_propagator(D, Prop)
  ),
  clpfd:trigger_once(Prop).
clpfd:run_propagator(clpfd_digits(N, Ds), MState):-
  (   maplist(is_digit0, Ds)
  ->  clpfd:kill(MState),
      digits_to_nonneg(Ds, N)
  ;   integer(N)
  ->  clpfd:kill(MState),
      nonneg_to_digits(N, Ds)
  ;   true
  ).
digits_to_nonneg([], 0):- !.
digits_to_nonneg(Ds, N):-
  maplist(char_weight, Chars, Ds),
  number_chars(N, Chars).
char_weight(Char, D):-
  char_type(Char, digit(D)).
nonneg_to_digits(0, []):- !.
nonneg_to_digits(N, Ds):-
  atom_chars(N, Chars),
  maplist(char_weight, Chars, Ds).
is_digit0(D):- integer(D), between(0, 9, D).

使用示例:

?- string_codes("12", Cs), phrase(day(D), Cs).
Cs = [49, 50],
clpfd_digits(D, [1, 2]).

正如您所看到的,约束没有计算为在D的值处推导。

+1对于此任务使用CLP(FD)约束!

forall/2和约束不能很好地混合,因为回溯会撤销发布的约束。

你的例子工作如预期的:

flip_init(Prop, D) :- clpfd:init_propagator(D, Prop).

和使用maplist(flip_init(Prop), Ds)代替forall/2

下一个问题是digits_to_nonneg([1,2], N)失败了,但这与实际的约束触发无关,实际的约束触发是按照预期发生的。(顺便说一下:使用约束,您可以简化代码,以便您可以在两个方向上使用单个谓词。)

同样,您可以使用in/2代替between/3: D in 0..9。如果您想将其用作约束而不仅仅是测试,这通常是有用的。

最新更新