如何统一序言中的两个基本术语

时间:2019-04-23 03:46:39

标签: prolog

我在序言中写了一个谓词: 计算(函数,A,值,表达式) 函数是一个函数可能具有变量A或没有变量 值是A的值,而Expr是Function的表达式。

例如:

Start Date:&emsp;<input class="txtStartDate" style="font: 13px/1.231 Trebuchet MS;" type="text" id="txtStartDate" name="Start Date" value="<%=currentDate%>" readonly><br><br> End Date: &emsp; <input class="txtEndDate" style="font: 13px/1.231 Trebuchet MS;" type="text" id="txtEndDate" name="txtEndDate" value="<%=defaultDate%>" readonly required/><br><br> <script> $(function() { $(".txtEndDate").datepicker({ changeMonth: true, changeYear: true, showOn: 'button', buttonImage: '../../../images/calendar.png', buttonImageOnly: true, title: 'Click to open calendar', alt: 'Click to open calendar' }); }); $(function() { $(".txtStartDate").datepicker({ changeMonth: true, changeYear: true, showOn: 'button', buttonImage: '../../../images/calendar.png', buttonImageOnly: true, title: 'Click to open calendar', alt: 'Click to open calendar' }); }); $('#txtStartDate').datepicker(); $('#txtEndDate').datepicker(); $('#txtStartDate').change(function() { var interval = 7; function convertDateString(p) { return (p < 10) ? '0' + p : p; } var startDate = new Date($(this).val()); startDate.setDate(startDate.getDate() + interval); $('#txtEndDate').val(startDate.getFullYear() + '/' + convertDateString(startDate.getMonth() + 1) + '/' + convertDateString(startDate.getDate())); }); </script> -返回E = 6。

calculate(2*3,x,2,E)-返回E = 4。

calculate(x+2,x,2,E)-返回E = 18。

calculate(2*(5+x*x),x,2,E)-返回E = x * 12。

calculate(x*(3+y*y),y,3,E)

上面的代码可以实现示例1,该示例在函数中没有变量,但是可以在函数具有变量时实现。

2 个答案:

答案 0 :(得分:1)

首先,您没有传递函数,而是传递了表达式,结果就是它们的计算结果。由于这是Prolog,并且我们可以自由地进行此类操作,因此我更喜欢传递类似x=2的一个参数,而不是传递两个x, 2的参数,因为我觉得它更具可读性。因此,我要查找的谓词看起来将更像evaluate(+Expression, +Var=Value, ?Result)

我们在这里应该做的是对表达式形状的归纳。因此,表达式的基本情况就是变量和数字,所以让我们先处理它们:

evaluate(Num, _, Num) :- number(Num).
evaluate(Var, Var=Value, Value).

其中的第一个应该很明显:如果我评估为3,我应该得到3,而我实际上并不在乎变量绑定是什么样子。

第二个可能看起来像是重言式,但是想法是,如果我正在寻找变量x的值并且我有一个看起来像x=3的绑定,那么结果是{{1 }}。

现在,您必须进行一些复制和粘贴。令人高兴的是,您可以在此处轻松创建Prolog本身未内置的函数。缺点是,它将有点重复。

3

因此,这里的想法是递归在一个运算符的左右分支上向下移动,然后在这两个边上应用该运算符。这个小小的玩具评估师将在非常简单的情况下工作,例如:

evaluate(A*B, Binding, Value) :-
    evaluate(A, Binding, AValue),
    evaluate(B, Binding, BValue),
    Value is AValue * BValue.

evaluate(A+B, Binding, Value) :-
    evaluate(A, Binding, AValue),
    evaluate(B, Binding, BValue),
    Value is AValue + BValue.

现在,您在这里遇到了一些麻烦,要正确处理会很烦人,这就是您要在此处执行的是对 partial 进行某种评估。有多个变量时的表达式。讨厌的例子是这样的:

?- evaluate(2*(5+x*x), x=2, E).
E = 18 

您真的希望它返回?- evaluate(x*(3+y*y), y=3, E). false. 。现在,玩具评估器有两个问题正在阻止这种情况。首先是,如果您正在寻找变量,并且不具有绑定,则不知道该怎么办,可以通过更改基本情况来解决:

x*12

这将立即导致一些错误:

evaluate(Var, X=Value, Result) :-
    atom(Var),
    (    Var = X -> 
         Result = Value 
    ; 
         Result = Var
    )

问题是ERROR: Arithmetic: `x/0' is not a function ERROR: In: ERROR: [9] _3344 is x*3 ERROR: [7] <user> ERROR: ERROR: Note: some frames are missing due to last-call optimization. ERROR: Re-run your program in debug mode (:- debug.) to get more detail. 要求右边的表达式除数字和运算符外不包含任何其他内容;它永远不会为您提供一棵树。我们可以尝试这样解决这个问题:

is/2

乍一看似乎可行:

evaluate(A*B, Binding, Value) :-
    evaluate(A, Binding, AValue),
    evaluate(B, Binding, BValue),
    (number(AValue), number(BValue) ->
        Value is AValue * BValue
    ;
        Value = AValue * BValue
    ).
evaluate(A+B, Binding, Value) :-
    evaluate(A, Binding, AValue),
    evaluate(B, Binding, BValue),
    (number(AValue), number(BValue) ->
        Value is AValue + BValue
    ;
        Value = AValue + BValue
    ).

但是,您将能够找到许多未发生代数运算的情况,这些情况会融合更多的常量:

?- evaluate(x*(3+y*y), y=3, E).
E = x*12 ;
false.

左常量因子不会与右常量因子相乘,因为这里我们没有任何树重排代码。正确的常数因子由于使用?- evaluate(3*3*x*3*3, y=3, E). E = 9*x*3*3 ; 可以更清楚地说明原因而未能合并:

write_canonical/1

您可能会由此猜测,最里面的常数被折叠在一起产生9 * x,然后我们尝试将其乘以三。由于?- write_canonical(3*3*x*3*3). *(*(*(*(3,3),x),3),3) 不是数字,因此不会与9*x一起折叠。现在,您在左侧有一个树桩,它也不会与下一个*3一起折叠。

以临时方式在这里解决所有问题将是令人不快的,但如果需要的话,您可以这样做。老实说,我不知道如何建立一个可以处理这些问题的合理完整的代数系统。我怀疑您需要比解析树更有效的数据结构,但是除此之外,我什么都不知道。无论如何,我希望这会有所帮助。

答案 1 :(得分:1)

这需要更多上下文。看来, real 目标是解析“函数”(带变量的算术表达式?)并将其简化。

Prolog免费为您提供大部分解析,这意味着2*x + 3之类的表达式也是有效的Prolog术语,甚至具有您期望的解析树:

$ swipl
Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.3-31-g32d2d0a1d)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.

For online help and background, visit http://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).

?- T = 2*x + 3*y, display(T).
+(*(2,x),*(3,y))
T = 2*x+3*y.

所以现在您需要弄清楚两件事:

  1. 您的语言定义如何:运算符是什么,优先级,值是什么,变量是什么,等等。
  2. 您如何简化?

第二点有潜力为您提供最多的工作。您现在似乎遇到的问题相对容易,但是您需要使用其他方法。您只需要遍历树并替换所有出现的“变量”(第二个参数中的值)和一个值(第三个参数中的值)。然后,您仍然必须简化。

要了解如何替换,可以尝试阅读“ Prolog的艺术”第3章“递归编程”。在第70-80页左右,甚至可以找到几乎可以使用的示例程序。也有一个完整的示例程序可以执行派生。这不是您所需要的,但是这种方法非常接近您可能需要的。

还有一个警告:当您在Prolog语境中说“功能”或“变量”时,对于Prolog思维方式的人来说,它们可能意味着不同的事情,因此您将彼此交谈一段时间。如果您可以将问题用较为正式的语言表达,则可能会更容易帮助您。