PROLOG 打印以 7 结尾且其数字之和大于 100 的数

PROLOG Print numbers that end in 7 and the sum of its digits is greater than 100

我需要创建一个谓词来接收数字列表并仅打印以 7 结尾且其数字之和大于 100 的数字

我为 separated 创建了谓词,但我需要帮助将两个谓词合并,我的意思是这两个谓词进入一个唯一的谓词,这就是我到目前为止所做的:

%sum of digits greater than 100
 multi(X):-
0 is X mod 100
sum([],0).
sum([P|Q],Z).
multi(P), sum(Q,Z1), Z is P + Z1.
sum([P|Q],Z).
not multi(P), sum(Q,Z).

%print the numbers that end in 7
end(Y):-
7 is Y mod 10.
listend([],0).
listend([P|Q]):-
end(P),write(P), nl, listend(Q).
listend([P|Q]):-
not(end(P)), listend(Q).

这对我有用:

?- filter([147, 24, 57, 17, 3667], X), write(X), nl, fail.

sumdigits(0, 0).
sumdigits(X, Z) :-
    X > 0,
    Z1 is X mod 10, 
    X2 is X // 10,
    sumdigits(X2, Z2), 
    Z is Z1 + Z2.

filter([], []).
filter([H|X], [H|Y]) :-
    sumdigits(H, D),
    D > 10,
    7 is H mod 10, !,
    filter(X, Y).
filter([_|X], Y) :- filter(X, Y).

我得到:

[147, 57, 3667]
No.

我以为你的意思是数字之和大于 10,而不是 100。

使用!

:- use_module(library(clpfd)).

我们这样做:

n_base10(N, Ds) :-
   n_base_digits(N, 10, Ds).

n_base_digits(Expr, Base, Ds) :-
   Base #> 1,
   Ds = [_|_],
   N #=  Expr,
   N #>= 0,                                   % N is non-negative
   n_base_ref_acc_digits(N, Base, Ds, [], Ds).

n_base_ref_acc_digits(N, Base, Ref, Ds0, Ds) :-
   zcompare(Order, N, Base),
   order_n_base_ref_acc_digits(Order, N, Base, Ref, Ds0, Ds).

order_n_base_ref_acc_digits(<, N,    _, [_]   , Ds0,   [N|Ds0]).
order_n_base_ref_acc_digits(=, _,    _, [_,_] , Ds0, [1,0|Ds0]).
order_n_base_ref_acc_digits(>, N, Base, [_|Rs], Ds0, Ds) :-
   N0 #= N //  Base,
   N1 #= N mod Base,
   n_base_ref_acc_digits(N0, Base, Rs, [N1|Ds0], Ds).

一些简单的查询1:

?- n_base10(_, []).
false.

?- X #< 0, n_base10(X, Ds).
false.

?- n_base10(123, [1,2,3]).
true.                                   

?- n_base10(123, Ds).
Ds = [1,2,3].

?- n_base10(N, [1,7,9]).
  N = 179
; false.

?- n_base10(459183754813957135135239458256, Ds).
Ds = [4,5,9,1,8,3,7,5,4,8,1,3,9,5,7,1,3,5,1,3,5,2,3,9,4,5,8,2,5,6].

使用 10 以外的基数怎么样?

?- member(Base,[2,8,10,16,36]), n_base_digits(N,Base,[1,2,3,4]).
  Base =  8, N =   668
; Base = 10, N =  1234
; Base = 16, N =  4660
; Base = 36, N = 49360
; false.

?- member(Base,[2,8,10,16,36]), n_base_digits(101,Base,Ds).
  Base =  2, Ds = [1,1,0,0,1,0,1]
; Base =  8, Ds =         [1,4,5]
; Base = 10, Ds =         [1,0,1]
; Base = 16, Ds =           [6,5]
; Base = 36, Ds =           [2,29].

好的!按预期工作。

让我们找出数字和大于 1007 作为最低有效小数位的整数!

?- set_prolog_flag(toplevel_print_anon, false).
true.

?- _S #> 100,
   n_base10(N, _Ds),
   lists:last(_Ds, 7),
   clpfd:sum(_Ds, #=, _S),
   clpfd:labeling([ff,min(N)], _Ds).
  N = 499999999997
; N = 589999999997
; N = 598999999997 
...

现在,关于您问题的 "filtering" 部分……它就像 1, 2, 3.

一样简单

首先,我们根据 . It fits the reification scheme (of if_/3, (=)/3, etc.) which already has been used in a lot of logically-pure Prolog answers on Whosebug.

定义(@)/2
@(G_0, T) :- @var(T), @G_0, T = true.

其次,我们定义 谓词 (#=)/2(#>)/2.

的具体化版本
#=(X, Y, T) :- X #= Y #<==> B, (B, T).

#>(X, Y, T) :- X #> Y #<==> B, bool01_t(B, T).

最后,使用Prolog lambdas, tfilter/3 and ','/3,我们查询:

?- use_module(library(lambda)).
true.

?- Zs0 = [                              /* Es: list of sample integers */
             499999999997,              /*     (digit sum = 101)       */
            9899999999970,              /*     (digit sum = 105)       */
          516666669999997,              /*     (digit sum = 103)       */
                  5000007,              /*     (digit sum =  12)       */
             598999999997               /*     (digit sum = 101)       */
         ],
   tfilter(\N^(                         /* N:  candidate integer       */
               @n_base10(N, Ds),        /* Ds: base-10 representation  */
               @lists:last(Ds, D1),     /* D1: least significant digit */
               D1 #= 7,                 /* D1:              equal to 7 */
               @clpfd:sum(Ds, #=, S),   /* S:  digit sum               */
               S #> 100                 /* S:         greater than 100 */
              ),
           Zs0,
           Zs).
Zs0 = [499999999997,9899999999970,516666669999997,5000007,598999999997],
Zs  = [499999999997,              516666669999997,        598999999997].

很有魅力!


脚注 1: 使用 SWI-Prolog 版本 7.3.10(64 位 AMD64)