如何识别 Prolog 术语的浪费表示

4
什么是Prolog谓词,可以帮助显示Prolog术语的浪费表示形式?

补充

在之前的Prolog SO答案中,我记得是由mat提供的一个Prolog谓词来分析Prolog术语并展示它过于复杂。

特别是对于像

[op(add),[[number(0)],[op(add),[[number(1)],[number(1)]]]]]

它揭示了这有太多的[]

我搜索了我的Prolog问题并查看了答案两次,仍然找不到它。我还记得它不在SWI-Prolog中,而是在另一个Prolog中,所以我能够使用Prolog的在线版本来使用谓词。

如果您阅读评论,您将看到mat确定了我正在寻找的帖子


我所追求的是什么

在选择表达方式方面,我有最后一点建议。请尝试以下内容,例如使用GNU Prolog或任何其他符合Prolog标准的系统:

| ?- write_canonical([op(add),[Left,Right]]). 
'.'(op(add),'.'('.'(_18,'.'(_19,[])),[]))

这表明这种表示方式相当 浪费,同时阻碍了对生成的所有表达式的统一处理,结合了几个缺点。

你可以通过使用Left+Right或使用op_arguments(add, [Left,Right])op_arguments(number, [1])等方法,使其更加紧凑和统一。


一个 Prolog 数据结构的演化

如果你还不知道,这个问题与在 Prolog 中编写一个符号数学术语重写系统有关,我目前主要集中于简化重写。

大多数人只看到以自然表示的数学表达式。

x + 0 + sin(y)

计算机程序员意识到大多数编程语言在使用前必须解析数学表达式并将其转换为AST。
add(add(X,0),sin(Y))

但是大多数编程语言不能直接使用上述AST,必须创建数据结构。参见: 编译器/词法分析器, 编译器/语法分析器, 编译器/抽象语法树解释器
现在,如果你在学习Prolog时不仅仅是浅尝辄止,那么你一定会遇到导数规则程序3.30,它包含在这里,但该人没有给出归属。
如果你试图使用Prolog编写自己的符号数学代码,你可能会尝试使用is/2,但很快就会发现它不起作用,然后发现Prolog可以将以下内容读取为复合术语
 add(add(X,0),sin(Y))

这开始运作,直到你需要访问函数对象的名称并找到functor/3,但随后我们又回到了需要解析输入的情况。不过正如mat所指出的以及在"Prolog艺术"中提到的,如果有人使结构的名称可访问,就可以避免这个问题。
 op(add,(op(add,X,0),op(sin,Y)))

现在,人们可以以Prolog友好的方式访问表达式中的运算符和术语。如果没有旁注的话,代码仍将使用嵌套列表数据结构,并且现在正在转换为使用公共项术语来公开结构名称。我想知道是否有一个常见的短语来描述这个,如果没有,应该有一个。无论如何,新的简单数据结构已经通过了第一组测试,现在需要看看它在项目进一步开发时是否能够保持稳定。

请在tutorialspoint.com上使用GNU Prolog进行在线尝试

:- initialization(main).
main :- write_canonical([op(add),[Left,Right]]).

然后点击执行并查看输出。
sh-4.3$ gprolog --consult  file main.pg  
GNU Prolog 1.4.4 (64 bits)  
Compiled Aug 16 201423:07:54 with gcc  
By Daniel Diaz  
Copyright (C1999-2013 Daniel Diaz  
compiling /home/cg/root/main.pg for byte code...  
/home/cg/root/main.pg:2: warning: singleton variables [Left,Right] for main/0  
/home/cg/root/main.pg compiled, 2 lines read - 524 bytes written, 9 ms  
'.'(op(add),'.'('.'(_39,'.'(_41,[])),[]))| ?-  

enter image description here


清晰表示与缺省表示的区别

来自《Prolog之力》(The Power of Prolog),作者:Markus Triska

在使用Prolog术语表示数据时,请问自己以下问题:

我能否通过最外层的函数符和元数区分每个成分的类型

如果满足这个条件,那么你的表示方法被称为是清晰表示。如果你不能通过它们的最外层函数符和元数来区分元素,则被称为缺省表示,这是一个将"default"和"faulty"组合起来的单词游戏。这是因为关于你的数据的推理需要一个"缺省情况",如果其他所有情况都失败了则应用它。此外,这种表示方法防止了参数索引,并且由于这一缺点被认为是有问题的。始终致力于避免缺省表示!而是努力寻求更清晰的表示方法。


1
一个术语是否“过于复杂”可能取决于上下文、用例和术语的语义含义。例如,如果您想表示单个原子a,您可以轻松地认为像[[a]]这样的表示方式过于复杂(列表结构是多余/不必要的)。然而,在更广泛的背景下,如果[[a]]是为给定应用程序定义的更复杂结构的微不足道的情况,那么它可能是合适的。那么...“过于复杂”的定义是什么? - lurker
2
请链接到Mat的帖子。 - false
1
@lurker 我认为更好的方法是避开将标题与Prolog术语联系起来的整个问题,而是只关注查找旧的SO答案。我看到的问题是该答案对他人有用,而标题是一个很好的注意力吸引者,在Google搜索中显示出来。请随意更改标题;正如我之前所指出的,我认为我在SO上的所有帖子都是公开和免费更改的,因为它们是创意共享的。 - Guy Coder
2
我认为这是一个关于Prolog信息表示的刺激性和有趣的问题,尽管它具有主观成分,但我很高兴你发表了它。构成良好(或者也许是高效)表示的因素可能是共同原则加上应用程序访问信息的需求的组合。 - lurker
1
而且...现在我们深入了解后,我不知道是否有更好的标题想法。所以我就不管它了。 :) - lurker
显示剩余13条评论
2个回答

4
请查看最后一部分:

https://dev59.com/vZ_ha4cB1Zd3GeqP5NAH#42722823

它使用write_canonical/1来显示一个项的规范表示形式。
当学习Prolog并帮助消除初学者的一些常见误解时,这个谓词非常有用。例如,在hyphens的最近问题中,它也会有所帮助。
请注意,在SWI中,输出通常与规范的Prolog语法不同,因此在解释Prolog语法时我不使用SWI。

1
您还可以通过编程方式计算单个元素列表的子项数量,例如使用以下代码(未经过优化):
single_element_list_subterms(Term, Index) :-
    Term =.. [Functor|Args],
    (   Args = []
    ->  Index = 0
    ;   maplist(single_element_list_subterms, Args, Indices),
        sum_list(Indices, SubIndex),
        (   Functor = '.', Args = [_, []]
        ->  Index is SubIndex + 1
        ;   Index = SubIndex
        )
    ).

尝试在示例复合术语上进行:

| ?- single_element_list_subterms([op(add),[[number(0)],[op(add),[[number(1)],[number(1)]]]]], Count).

Count = 7

yes
| ?-

表明有7个子项,由单元素列表组成。这是write_canonical的结果:
| ?- write_canonical([op(add),[[number(0)],[op(add),[[number(1)],[number(1)]]]]]).
'.'(op(add),'.'('.'('.'(number(0),[]),'.'('.'(op(add),'.'('.'('.'(number(1),[]),'.'('.'(number(1),[]),[])),[])),[])),[]))

yes
| ?-

谢谢。很好的例子。希望其他人能从中学习,或者至少在不理解时提出问题。 - Guy Coder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接