术语扩展:一个术语列表的处理方法

5

假设我想要一些遵循相同模式的规则。当我想要避免非确定性行为并显式列出所有可能的第一个参数时,我会遇到这种情况。但是,我知道对于某些可能性,我需要完全相同的操作。处理这种情况的一种方法是在最后添加一个通配符子句:

foo(a) :- /* do something */.
foo(b) :- /* do something else*/.
foo(_). /* ignore the rest */

但这并不是很好,因为我无法知道是否收到了意外的输入,还是我在程序中犯了错误。为了避免这种情况,我也可以这样说。
foo(X) :- memberchk(X, [ /* list of possible values of X */ ]).

但是,我现在正在与Prolog的确定性行为和索引抗争,尤其是当参数是ground时。

因此,我会采取以下方式:

term_expansion(foos(Foos), Foo_rules) :-
    maplist(expand_foo, Foos, Foo_rules).

expand_foo(Foo, foo(Foo)).
other_foos([x,y,z]).

问题是,我试图找到类似的代码,但没有成功。这是因为我做错了什么吗?有更好的方法来解决这个问题吗?或者完全绕过它?
我不介意答案说“你正在解决错误的问题”。
编辑:一些谷歌搜索实际上让我找到了 SWI-Prolog 文档中非常相似的示例:http://www.swi-prolog.org/pldoc/man?section=ext-dquotes-motivation(在最底部)。

SWI-Prolog文档中的示例并不完全适用:它详尽地列举了所有情况,不需要默认情况。 - mat
@mat 是的,但是我想要的想法是枚举默认情况下可能的参数.... - user1812457
如果可以的话,那就是我也会这样做的。 - mat
1个回答

5

首先,对于您已经提出的几个方案,我有一些评论:

foo(a) :- /* do something */.
foo(b) :- /* do something else */.
foo(_).   /* ignore the rest */

这样做的主要问题在于最后一句子(foo(_))会在其他 - 可能更加专业化的 - 句子也适用时生效。因此,查询 ?- foo(a). 现在变得意外地非确定性。
你说这个版本“不太好,因为我实际上无法知道是否获得了意外的输入,或者是否在程序中出现错误”。我们可以通过确保在检查所有语句时给定的术语不是意外情况来防范意外情况:
foo(a) :- /* do something */.
foo(b) :- /* do something else */.
foo(X) :- must_be(oneof([a,b,x,y], X).

当术语形式不符合预期时会引发错误。我以xy为例,说明没有特殊处理的术语。请注意,必须包括ab,因为该条款(再次)也适用于它们两个。即使实例化了参数,谓词仍然不确定,因为第一个参数索引无法区分情况。您写道“现在我正在与Prolog的确定性行为和索引做斗争,当参数ground时,您可能(并且正确地)意味着在使用此表示时无法从这些特性中受益。”

现在是漂亮的声明性解决方案:每当您想引入“ catch-all”或“ default”条款时,请重新考虑数据表示,并引入可应用的不同情况的区分functors。在您的示例中,两种情况是:

  1. 需要以特殊方式处理术语
  2. 不需要对该术语执行任何特殊操作。

我将使用special(_)ordinary(_)来区分这些情况。这样:

foo(special(S)) :- foo_special(S).
foo(ordinary(_)). % do nothing

foo_special(a) :- /* do something      */
foo_special(b) :- /* do something else */

这些谓词可以在所有方向上使用,并且在已知参数时是确定性的。可以轻松添加类型检查。

1
我喜欢这个建议(+1),但它是否意味着我需要在之前的步骤中显式处理我的abxy?在我的特定情况下,我正在解析文本;然后,在那一点上,我将不得不明确处理每个默认和特殊情况....实际上,我正在标记标签!此外,请参阅编辑后的问题以获取先例。 - user1812457
4
通常在程序的早期阶段,会有一个小的步骤,将默认结构转换为非默认结构,通常是在接收用户输入(来自文件或终端)后直接进行。这部分通常会使用非单调的控制结构,如if-then-else、cuts等,但好处是:一旦你的数据以清晰的方式表示出来,就可以在程序的(大部分)剩余部分中完全使用模式匹配来处理它!你正在为你的数据打标签,而不是标签本身。 - mat

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