【问题标题】:Constraint not propagated upon instantiation of list members实例化列表成员时未传播约束
【发布时间】:2015-06-07 04:20:34
【问题描述】:

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

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

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

在 SWI-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 的值处派生。

【问题讨论】:

  • 请参阅this answer 了解解决相关问题的 clpfd 方法。
  • when((ground(Codes);nonvar(N)), number_codes(N,Codes)) 相比,您期望获得什么?两者都是弱关系而不是关系 - 就此而言。
  • @false 非常接近!但是它不处理填充零,例如,phrase(day(2), "02")
  • 我看不出这个目标有什么问题,前提是set_prolog_flag(double_quotes, codes)
  • 错误在于code_type:它失败了:code_type(C,digit(N)),N=0.但成功了N=0, code_type(C,digit(N)).

标签: parsing prolog clpfd


【解决方案1】:

+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/3D in 0..9。如果您想将其用作约束而不仅仅是测试,这通常很有用。

【讨论】:

  • 三个赞成票中的任何一个是否真的测试生成的代码?其中还有很多错误。就像两个切口一样。
  • 我当然没有:在回答了实际问题(触发传播者)之后,我什至没有尝试纠正之后发现的第一个错误(digits_to_nonneg/2意外失败),更不用说更远了。编写正确的传播器本身当然值得提出几个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-28
相关资源
最近更新 更多