Prolog 组合函数

Prolog Combination Function

我在 prolog 中编写组合函数时遇到了麻烦,它遵循以下数学方程式:b! / ((b-c)! * c!) 我是 prolog 的新手,不确定它到底有什么问题。我收到的错误是:ERROR: is/2: Arithmetic: `fact1/2' is not a function

下面是我的代码:

    %fac(0,1).
    %fac(N,X) :- N > 0, M is N - 1, fac(M,Y), X is Y * N.

    fact1(0,Result) :- Result is 1.
    fact1(N,Result) :- N > 0, N1 is N-1,                                                 
    fact1(N1,Result1), Result is Result1*N.

    main :- current_prolog_flag(argv,[BB_S,CC_S]),
        atom_number(BB_S,BB),
        atom_number(CC_S,CC),
        %read_input,
        R1 is 1,
        R2 is 1,
        R3 is 1,
        FB is fact1(BB,R1),
        ABS is abs(BB - CC),
        FE is fact1(ABS,R2),
        FC is fact1(CC,R3),
        TI is FE * FC,
        BF is FB / TI,
        %BF is fac(BB) / (fac(abs(BB-CC)) * fac(CC))),
        write($BF),
        halt.

感谢您的帮助。

没关系。我找到了解决办法。但是,为了其他人的利益,我已经在此处发布了解决方案。显然,这些函数没有 return 和 return,而是将它们生成的值放在给定变量中。

    %fac(0,1).
    %fac(N,X) :- N > 0, M is N - 1, fac(M,Y), X is Y * N.

    fact1(0,Result) :- Result is 1.
    fact1(N,Result) :- N > 0, N1 is N-1, fact1(N1,Result1), Result is Result1*N.

   main :- current_prolog_flag(argv,[BB_S,CC_S]),
       atom_number(BB_S,BB),
       atom_number(CC_S,CC),
       %read_input,
       fact1(BB,FB), %notice change
       ABS is abs(BB - CC),
       fact1(ABS,FE), %notice change
       fact1(CC,FC), %notice change
       TI is FE * FC,
       BF is FB / TI,
       %BF is fac(BB) / (fac(abs(BB-CC)) * fac(CC))),
       print('Number of bracelets: '),
       write(BF),
       halt.

根据问题,我认为您对什么是谓词有误解。谓词只能导致 truefalse(当然可能会出现错误,或者如果您也将它们视为 "possible outcomes",它们可能会永远循环)。谓词可以通过 统一 尚未固定的变量来响应值。通常在 Prolog 中,使谓词尽可能通用,这样就可以调用谓词 multidirectional.

你这样调用谓词:

FB is fact1(BB,R1),

但是 fact1 不是函数(在 is/2 谓词中语义已知的函子)。

谓词可以计算事物,通过统一传递结果,例如:

?- fac1(5, X).
X = 120 .

我们因此调用fac1/2谓词,第一个参数固定为5,Prolog会将X统一为120

我们可以将谓词重写为:

main :- current_prolog_flag(argv,[BB_S,CC_S]),
    atom_number(BB_S,BB),
    atom_number(CC_S,CC),
    fact1(BB, <b>FB</b>),
    ABS is abs(BB - CC),
    fact1(ABS, <b>FA</b>),
    fact1(CC, <b>FC</b>),
    Res is <b>FB</b> / (<b>FA</b> * <b>FC</b>),
    write(Res).

我们还可以使 fac1 更具声明性:现在它仅在第一个参数固定的情况下有效(或者在第二个参数为 1 的情况下)。此外,它的效率有点低,因为它没有使用 尾调用优化 (TCO)。我们可以使用 clpfd 库来改进谓词,并像这样实现它:

:- use_module(library(clpfd)).

fac(0, 1).
fac(I, F) :-
    I #> 0,
    F #= I*F1,
    I1 #= I-1,
    fac(I1, F1).

现在我们可以查询几个方向的阶乘关系:

?- fac(I, 120).
I = 5 ;
false.

?- fac(I, 130).
false.

?- fac(5, 120).
true ;
false.

?- fac(7, 120).
false.

?- fac(7, Y).
Y = 5040 ;
false.

因此我们可以查询 ii! 等于 120

我们还可以通过针对特定范围实施产品来提高性能,因此:

  b
------
 | |
 | |   i
i=a+1

所以 prodrange 基本上是:

prodrange(A, B, P) :- fac(A, FA), fac(B, FB), P 是 FB / FA.

但效率更高,因为这是 O(a + b),我们可以将其减少到 O(b - a),其中:

prodrange(A, A, 1).
prodrange(A, B, P) :-
    B > A,
    B1 is B-1,
    prodrange(A, B1, P1),
    P is P1 * B1.

或更多声明:

prodrange(A, A, 1).
prodrange(A, B, P) :-
    B #> A,
    P #= B*P1,
    B1 #= B-1,
    prodrange(A, B1, P1).

那么我们可以实现一个comb/3谓词来计算组合的数量:

comb(BB, CC, Res) :-
    MX is max(BB, CC),
    MN is min(BB, CC),
    prodrange(MN, MX, Num),
    Abs is MX-MN,
    fac(Abs, Den),
    Res is Num / Den.

那么 main 看起来像:

main :-
    current_prolog_flag(argv,[BB_S,CC_S]),
    atom_number(BB_S,BB),
    atom_number(CC_S,CC),
    comb(BB, CC, BF),
    print('Number of bracelets: '),
    write(BF),
    halt.