所以我刚刚开始学习Prolog这个学期,并且做了一个基本的工作来实现一个非常基本的d(function, variable, derivative),我这样做:
d(X,X,1) :- !.
d(C,X,0) :- atomic(C). %, (C \= X).
d(X**E,X,E*X**(E-1)).
d(U+V,X,A+B) :- d(U,X,A), d(V,X,B).
d(U-V,X,A-B) :- d(U,X,A), d(V,X,B).
d(U*V,X,DU*V+U*DV) :- d(U,X,DU), d(V,X,DV).
d(U/V,X,(DU*V-U*DV)/(V*V)) :- d(U,X,DU), d(V,X,DV).
Run Code Online (Sandbox Code Playgroud)
我知道这不完整,但它涵盖了练习中所需的所有任务.
但是,
?- d((x*x+2*x+3)/(3*x),x,R).
导致
R = ((1*x+x*1+ (0*x+2*1)+0)* (3*x)- (x*x+2*x+3)* (0*x+3*1))/ (3*x* (3*x)).
这看起来并不漂亮.是/ 2不幸的是不喜欢我的x,因为它不是一个数字...
是否有一个简单的解决方案来实现更清洁的结果?
我宁愿将其视为两个独立的问题:
首先,正确推导(您可能已经接近了,具体取决于您的具体要求)。
然后,在代数层面上简化表达式。利用代数恒等式,看看在某些子表达式上应用交换律/结合律/分布律是否能够将它们重写为等价的东西(但更简单/更紧凑)。
作为起点,您可能想看看有点相关的问题“ Replacing parts of expression in prolog ”。
下面是如何进行简化的简单草图 - 用于iwhen/2防止实例化不足:
expr_simplified(A, B) :-
iwhen(地面(A),xpr_simplr(A,B))。
xpr_simplr(A, B) :-
(原子(A)
-> A = B
; (A=X+0;A=0+X;A=1*X;A=X*1)
-> xpr_simplr(X, B)
; ( A = 0*_ ; A = _*0 )
-> B = 0
; A=X+X
-> B = X*2
; A = X*X
-> B = X**2
; A = X**1
-> B = X
; A =.. [F|Xs0], %默认包罗万象
映射列表(xpr_simplr,Xs0,Xs),
B =.. [F|Xs]
)。
让我们看看它对您给出的表达式有何作用。我们应用expr_simplified/2直到达到一个固定点:
?- A = ((1*x+x*1+(0*x+2*1)+0)*(3*x)-(x*x+2*x+3)*(0*x+ 3*1))/(3*x*(3*x)), expr_simplified(A,B), expr_simplified(B,C), expr_simplified(C,D)。 A = ((1*x+x*1+(0*x+2*1)+0)*(3*x)-(x*x+2*x+3)*(0*x+3* 1))/(3*x*(3*x)), B = ((x+x+(0+2))*(3*x)-(x**2+2*x+3)*(0+3))/(3*x)**2, C = ((x*2+2)*(3*x)-(x**2+2*x+3)*3)/(3*x)**2, D = C.达到 固定点百分比
尽管简化器并不完美,但表达式的可读性却提高了很多。