关于prolog:在其数字中拆分数字,以所有可能的方式分组

Split Number in its digits, grouped in all possble ways

我有一个数字,假设是 123,我想生成一组所有可能的拆分方式:

1
[[1, 23], [12, 3], [1, 2, 3]].

我想过创建 [1,2,3] 的幂集:

1
2
?- findall(Powerset, powerset([1,2,3], Powerset), Z).
Z = [[1], [1, 2], [1, 2, 3], [2], [2, 3], [3]].

然后将集合组合在一起并用append/3检查它们的连接是否是初始集合[1,2,3],即

1
2
3
[[1], [2, 3]] -> [1, 23]
[[1, 2], [3]] -> [12, 3]
[[1], [2], [3]] -> [1, 2, 3]

您是否想到了另一种更简单(更优雅)的解决方案?

我使用来自 gnu Prolog powerset 修改的这个谓词

1
2
3
4
powerset(L, [H|T]):-
  append([H|T], _, L).
powerset([_|L], P):-
  powerset(L, P).

我们可以有一个更集中的谓词来代替 powerset

1
2
3
4
5
parts(C, [C]).
parts(L, Ps) :-
    append(H, T, L), H \\= [], T \\= [],
    parts(T, Ts),
    append([H], Ts, Ps).

现在

1
2
3
4
5
?- number_codes(123,Cs),parts(Cs,Ps),maplist(number_codes,Ns,Ps).
Cs = [49, 50, 51],
Ps = [[49, 50, 51]],
Ns = [123] ;
...etc...

所以我们可以用 findall

收集有趣的 Ns

1
2
?- findall(Ns,(number_codes(123,Cs),parts(Cs,Ps),maplist(number_codes,Ns,Ps)),Rs).
Rs = [[123], [1, 23], [1, 2, 3], [12, 3]].

这里不需要使用findall/3---使用dcg!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int_split(X) -->
   int_split__aux(X,10,[]).

int_split__aux(X,P,Ds) -->
   (  { X =:= 0 }
   -> [Ds]
   ;  { X < P }
   -> [[X|Ds]]
   ;  { X0 is X mod P,
        X1 is X div P },
      int_split__aux(X1,10,[X0|Ds]),
      { P1 is P*10 },
      int_split__aux(X,P1,Ds)
   ).

示例使用:

1
2
3
4
5
?- phrase(int_split(123),Zss).
Zss = [[1,2,3], [12,3], [1,23], [123]].

?- phrase(int_split(1234),Zss).
Zss = [[1,2,3,4], [12,3,4], [1,23,4], [123,4], [1,2,34], [12,34], [1,234], [1234]].