如何解决目标/查询中变量数量变化时的问题-Prolog Constraint Solver

如何解决目标/查询中变量数量变化时的问题-Prolog Constraint Solver,prolog,logic,clpfd,cryptarithmetic-puzzle,Prolog,Logic,Clpfd,Cryptarithmetic Puzzle,下面是一个关于使用prolog约束求解机制解决经典SENDMORY crypt算术问题的片段- :- lib(ic). sendmore(Digits) :- Digits = [S,E,N,D,M,O,R,Y], Digits :: [0..9], alldifferent(Digits), S #\= 0, M #\= 0, 1000*S + 100*E + 10*N + D + 1000*M + 100*O + 10*R + E #= 10000*M + 1000*O + 100*N +

下面是一个关于使用prolog约束求解机制解决经典SENDMORY crypt算术问题的片段-

:- lib(ic).
sendmore(Digits) :-
Digits = [S,E,N,D,M,O,R,Y],
Digits :: [0..9],
alldifferent(Digits),
S #\= 0,
M #\= 0,
1000*S + 100*E + 10*N + D 
+ 1000*M + 100*O + 10*R + E
#= 10000*M + 1000*O + 100*N + 10*E + Y,
labeling(Digits).
现在,要执行此操作,我将发送如下目标/查询:

?- sendmore(Digits).
这将返回数字的可能解决方案

现在,我的问题是,我不想用这种方式对变量(比如S,E,N,…)进行“硬编码”,但是目标/查询会给出变量的数量。例如,如果我传递的查询类似于:

?- sendmore(S,E,N,D,M).
然后,它应该只计算SENDM的值,并假设其他变量不适用,因此将0分配给这些变量,然后继续计算。下次查询时,我可能会在查询中传递不同数量的变量。。例如:

?- sendmore(S,N,D,M,O,Y).
程序也应该这样计算

我试图实现的是针对上述场景的更一般化的问题解决方案。非常感谢您对这方面的指导。我对prolog非常陌生,正在使用ECLIPSE约束求解器。 谢谢。

这里有两个想法:

  • 您可以使用不同数量的参数定义sendmore(),这将调用“真实”版本,并填入缺少的参数。但是不能有不同版本的参数数量相同,但参数数量不同(因为Prolog会按位置将参数与参数匹配)
  • 您可以扩展/复杂化列表格式,以允许指定要传递的参数;在中间的例子中,有一行
    [(s,s),(e,e),(n,n),(d,d),(m,m)]
    。有点乏味,但给了你似乎想要的灵活性

  • 通常,目标中的变量和子句头中的变量是由它们的位置匹配的,而不是由它们的名称匹配的。因此调用
    ?-sendmore0([S,E,N,D,M])。
    应实现为:

    sendmore0([S,E,N,D,M]) :- sendmore([S,E,N,D,M,_,_,_]).
    
    然而,这意味着您需要为每种可能的组合实现这一点

    如果你真的想实现你所描述的,那么你需要给变量起一个稳定的名字。在ECLiPSe中,您可以使用库
    var\u name
    来实现这一点。这是一个相当的黑客,虽然

    :- lib(var_name).
    
    sendmore0(L) :-
       build_arg(["S","E","N","D","M',"O","R","Y"], L, A),
       sendmore(A).
    
    build_arg([], _, []) :- !.
    build_arg([H|T], L, [HA|HT]) :-
       match_arg(L, H, HA),
       build_arg(T, L, HT).
    
    match_arg([], _, _). % or use 0 as last argument if you want
    match_arg([H|T], Base, A) :-
       (
          get_var_name(H, S),
          split_string(S,"#","",[Base,_])
       ->
          A = H
       ;
          match_arg(T, Base, A)
       ).
    
    然后可以使用较短的变量列表调用
    sendmore0/1
    。别忘了设置变量名

    ?- set_var_name(S, "S"), set_var_name(E, "E"), sendmore0([S, E]).
    S = 9
    E = 5
    Yes (0.00s cpu, solution 1, maybe more)
    

    免责声明:这不是稳定名称的作用。它们用于调试目的。如果约阿希姆看到这一点,他会给我一个尖锐的耳环……

    我很难掌握可用的工具,并将它们应用于非常简单的问题,你是在概括解决方案之后。祝你好运