【问题标题】:Is "almost pure" Prolog expressive?“几乎纯粹”的 Prolog 是否富有表现力?
【发布时间】:2021-04-02 03:59:48
【问题描述】:

@false评论earlier

是的,您可以在没有dif/2 的情况下实现图灵机。但是你甚至不能实现交集或类似的谓词。

假设我们用call/Ndif/2(=)/3扩展纯Prolog(HornFOL+CWA+UNA),以用于if_/3,是否还有是其表达能力上的差距,Scheme 中定义的东西是微不足道的,但在这种扩展的(几乎是纯粹的)Prolog 中更难说明?

特别是,这样的 Prolog 是否允许像 Scheme 允许操作 Scheme 列表一样方便地操作 Prolog 列表?


编辑:假设方案没有突变、宏、延续、惰性、流、数字、字符串、向量或字符。只是符号、布尔值和列表(树)。

【问题讨论】:

  • (is)/2 怎么样?您几乎需要实例化错误、nonvar/1 和 ground/1 来防止意外使用。
  • @false 我在考虑没有数字、字符串或字符的方案。只是符号。我将进行编辑以澄清。

标签: prolog programming-languages logic-programming prolog-dif logical-purity


【解决方案1】:

只是符号和列表(树)。

如果您不想在纯 lambda 演算中编码所有内容,您还需要 Scheme 布尔值 #t#f。您还排除了函数值,谢天谢地,这使这个答案更简单。尽管您必须允许顶级(define name (lambda ...)) 表单的特殊情况。 (任何其他内容,包括扩展的let 表达式,都可以是defunctionalized。)

所以,我的主张是:,这个模糊的 Scheme 子集和你定义的纯 Prolog 在表达能力上没有差距。通过将列表交集的 Scheme 代码从 this answer 转换为 Prolog,我的论点(这不是证明)是有建设性的。

具体来说,这个:

(define intersect
  (lambda (set1 set2)
    (cond
      ((null? set1)(quote ()))
      ((member? (car set1) set2)
       (cons (car set1)
             (intersect (cdr set1) set2)))
      (else (intersect (cdr set1) set2)))))

变成:

intersect(Set1, Set2, Result) :-
    cond([
        ['null?'(Set1), result([])],
        [cond_1(Set1, Set2), body_1(Set1, Set2)],
        [else, body_2(Set1, Set2)]], Result).

cond_1(Set1, Set2, Result) :-
    car(Set1, Car),
    'member?'(Car, Set2, Result).

body_1(Set1, Set2, Result) :-
    car(Set1, Car),
    cdr(Set1, Cdr),
    intersect(Cdr, Set2, PartialIntersection),
    cons(Car, PartialIntersection, Result).

body_2(Set1, Set2, Result) :-
    cdr(Set1, Cdr),
    intersect(Cdr, Set2, Result).

还有这个:

(define member?
  (lambda (a lat)
    (cond
      ((null? lat) #f)
      (else (or (equal? (car lat) a) 
                (member? a (cdr lat)))))))

变成:

'member?'(A, Lat, Result) :-
    cond([
        ['null?'(Lat), result('#f')],
        [else, or([or_case_1(Lat, A),
                   or_case_2(Lat, A)])]], Result).

or_case_1(Lat, A, Result) :-
    car(Lat, Car),
    'equal?'(Car, A, Result).

or_case_2(Lat, A, Result) :-
    cdr(Lat, Cdr),
    'member?'(A, Cdr, Result).

请注意,嵌套表达式需要是非嵌套的,除了最简单的情况外,通过定义辅助 Prolog 谓词,这是最简单的。这不会非线性地增加代码大小。

这些定义使用标准 Scheme 构造的以下翻译:

'equal?'(X, Y, '#t') :-
    =(X, Y, true).
'equal?'(X, Y, '#f') :-
    =(X, Y, false).

'null?'(Value, Result) :-
    'equal?'(Value, [], Result).

car([Car | _Cdr], Car).

cdr([_Car | Cdr], Cdr).

cons(Car, Cdr, [Car | Cdr]).

or([], '#f').
or([Goal | Goals], Result) :-
    if(Goal,
       Result = '#t',
       or(Goals, Result)).

cond([], _Result) :-
    throw(error(cond_without_else, _)).
cond([[Condition, Body] | OtherCases], Result) :-
    if(Condition,
       call(Body, Result),
       cond(OtherCases, Result)).

一些支持从 cond 案例主体和 else 案例中获取简单值的东西:

result(Result, Result).

else('#t').

这就是您需要的所有内部不纯、外部纯 Prolog 支持:

if(Goal, True, False) :-
    call(Goal, Truth),
    (   Truth == '#t' -> call(True)
    ;   Truth == '#f' -> call(False)
    ;   throw(error(type_or_instantiation_error(Truth), _)) ).

我将其称为if/3 而不是if_/3,因为它不完全是“标准”if_/3:它期望条件评估为 Scheme 真值而不是 truefalse。随意将其按摩成“标准”形式。 编辑:有几种“足够好”的方法来定义(=)/3,这将在这个答案的上下文中起作用,但为了避免进一步的自行车脱落,只需使用来自https://stackoverflow.com/a/27358600/4391743 的定义。

测试:

?- 'member?'(a, [x, y, a, c], Result).
Result = '#t' ;
false.

?- intersect([a, b, c, d], [c, d, e, f], Result).
Result = [c, d] ;
false.

【讨论】:

  • (=)/3 不纯。
  • 在帖子假设所有Scheme值都是基础的情况下,这已经足够纯粹了。我的意思是在答案中添加它,我会更新它。在任何情况下,将我的(=)/3 替换为stackoverflow.com/a/27358600/4391743 的完整定义会使程序的行为相同。
  • 不需要 dif/2。相反,实例化错误会使其非常安全。
  • “在帖子假设所有 Scheme 值都是基础的情况下,这已经足够纯粹了。” 这不是假设。如果您要将 Scheme 过程转换为 Prolog 谓词,它必须使用地面“输入”正确工作(如 Scheme),但它可能适用于非地面(为什么要使用(几乎纯)Prolog 否则?)实际假设在第一段中说明。
  • “你还需要 Scheme 布尔值” 已添加,谢谢。虽然我认为布尔值并不重要。其他 Lisps 使用'T() 来表示#t#f
【解决方案2】:

symbol/1dif/2 是逻辑纯 Prolog 的充分扩展。

证明:

This answer 包含 Scheme 表达式的求值器 evil/2。它理解lambdaquote,并且可以很容易地扩展来处理内置的列表过程,如listcarcdr等。除了纯(喇叭)Prolog,它只使用symbol/1dif/2。虽然它是一个解释器并且运行缓慢,但它的存在表明 Scheme 所做的相同列表操作可以在这种几乎纯 Prolog 中完成。 (我认为symbol/1 也不需要,如果将Scheme 符号转换为symb(prolog_atom) 而不是直接转换为prolog_symbol


编辑

这将evil/2 扩展为处理if#t#f(由truefalse 表示):

evil(true, _, true).
evil(false, _, false).

evil([if, E1, E2, E3], Env, Val) :-
    evil(E1, Env, false),
    symbols(E2),
    evil(E3, Env, Val).

evil([if, E1, E2, E3], Env, Val) :-
    evil(E1, Env, V),
    dif(V, false),
    symbols(E3),
    evil(E2, Env, Val).

这扩展了evil/2 以处理equalp。它甚至比 Scheme 的 eq* 更强大,因为它也等同于一些闭包:

evil([equalp, E1, E2], Env, true) :-
    evil(E1, Env, V),
    evil(E2, Env, V).

evil([equalp, E1, E2], Env, false) :-
    evil(E1, Env, V1),
    evil(E2, Env, V2),
    dif(V1, V2).

【讨论】:

  • 这是一个不包括任何形式的 cond 或相等测试的 Scheme 表达式的求值器。鉴于 等式测试是实现列表交集的根本问题,这个“证明”并不能说明你认为它做了什么。
  • @IsabelleNewbie intersection 的问题是缺少 disequality。但是,这个 Q 特别允许dif/2。我认为evil/2 可以简单地扩展以处理条件语句(使用(=)/2dif/2)。
  • @IsabelleNewbie 添加了if#t#f。 (尽管我记得一些关于 lambda-calculus 不需要它们的讨论)——可能是错误的 w.r.t。当您执行 (lambda (#t)..) 时会发生什么,但如果是这样,应该可以修复。
  • “虽然我记得一些关于 lambda 演算如何不需要它们的讨论” 它不需要它们,因为你可以想出一种方法将它们编码为 lambda,就像您可以将自然数、列表和其他所有内容编码为 lambda 一样。但是如果你是那种还原论者,你最初的问题就变得毫无意义:我们知道你可以在图灵机中编码 Scheme,所以你可以在 Prolog 中编码也就不足为奇了。
  • 无论如何,这仍然缺少equal?,为此您需要某种确定相等性的方法,例如(=)/3
【解决方案3】:

如果您采用纯方案。可能纯 Prolog 就足够了。 Pure Scheme 将是具有某种严格的按值调用评估策略的 lambda 表达式。所以我们可以在Prolog中实现纯Scheme,借鉴deBruijn indexes

eval(P*Q, H) :- !,
   eval(P, R),
   eval(Q, S),
   reduce(R, S, H).
eval(X, X).

reduce(b(R), S, J) :- !,
   subst(R, 0, S, H),
   eval(H, J).
reduce(R, S, R*S).

如果你稍微改变一下表示,我想你可以摆脱削减。也许通过皮亚诺公理做必要的算术。嗯,你在纯 Prolog 中得到了纯 Scheme。

这是一个示例查询,SUCC 和 ZERO 来自here

?- ZERO = b(b(0)), SUCC = b(b(b(1*(2*1*0)))), 
   eval(SUCC*(SUCC*ZERO)*f*a, X).
ZERO = b(b(0)),
SUCC = b(b(b(1*(2*1*0)))),
X = f*(f*a)

【讨论】:

  • 在Scheme中,您可以简单地进行if-then-elseish测试是否相等。在没有 dif/2 的 Prolog 中不是这样。
  • dif/2 祝你好运,在 SWI-Prolog 中你不能将它与 unify_with_occurs_check/2 结合使用,请参见此处:stackoverflow.com/q/65532899/502187
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-01
  • 1970-01-01
  • 2011-08-14
  • 1970-01-01
  • 2012-01-09
  • 1970-01-01
  • 2012-05-07
相关资源
最近更新 更多