术语列表的术语扩展

5 macros metaprogramming prolog prolog-defaulty

假设我想要有许多遵循相同模式的规则。当我想通过显式列出所有可能的第一个参数来避免不确定性行为时,我遇到了这种情况。然而,我知道我需要对某些可能性做同样的事情。处理这个问题的一种方法是在末尾添加一个包罗万象的子句:

foo(a) :- /* do something */.
foo(b) :- /* do something else*/.
foo(_). /* ignore the rest */
Run Code Online (Sandbox Code Playgroud)

但这不太好,因为我实际上无法知道是否收到了意外的输入,或者我的程序是否犯了错误。为了避免这种情况,我还可以说

foo(X) :- memberchk(X, [ /* list of possible values of X */ ]).
Run Code Online (Sandbox Code Playgroud)

但我现在再次反对 Prolog 的确定性行为和当论证成立时的索引。

所以,相反,我做了这样的事情:

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

expand_foo(Foo, foo(Foo)).
other_foos([x,y,z]).
Run Code Online (Sandbox Code Playgroud)

问题是,我试图找到这样的现有代码,但我找不到。是因为我做错了什么吗?有没有更好的方法来解决这个问题?或者完全规避它?

我不介意“你正在解决错误的问题”的答案。

编辑:一些谷歌搜索实际上让我从 SWI-Prolog 文档中找到了这个非常相似的示例:

http://www.swi-prolog.org/pldoc/man?section=ext-dquotes-motivation (在最底部)

mat*_*mat 5

首先对您已经建议的变体进行一些评论:

foo(a) :- /* do something */.
foo(b) :- /* do something else */.
foo(_).   /* ignore the rest */
Run Code Online (Sandbox Code Playgroud)

这样做的主要问题是,foo(_)当其他(可能更专业的)子句也适用时,最后一个子句 ( )适用。因此,查询?- foo(a).现在无意中具有不确定性。

你说这个版本“不是很好,因为我实际上不知道是否得到了意外的输入,或者我的程序是否犯了错误”。我们可以通过确保在 check-all 子句中给定的术语不是意外的来防止意外输入:

foo(a) :- /* do something */.
foo(b) :- /* do something else */.
foo(X) :- must_be(oneof([a,b,x,y], X).
Run Code Online (Sandbox Code Playgroud)

当该术语具有意外形式时,这会引发错误。我使用xandy作为未特别处理的术语的示例。请注意,当然必须包含ab,因为该子句(再次)也适用于它们两者。即使实例化其参数,谓词仍然不是确定性的,因为第一个参数索引无法区分情况。您写道“我现在正在与 Prolog 的确定性行为和索引进行斗争,当论证成立时”,并且可能(并且正确地)意味着当您使用这种表示形式时,您无法从这些功能中受益。

现在是一个很好的声明性解决方案:每次您想引入“包罗万象”或“默认”子句时,请重新考虑您的数据表示,并为可以应用的不同情况引入区分函子。在您的示例中,两种情况是:

  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 */
Run Code Online (Sandbox Code Playgroud)

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

  • 是的,程序中通常会有一个小的早期步骤,将默认结构转换为非默认结构,通常是在收到用户输入(来自文件或终端)后直接进行。这部分通常会使用非单调控制结构,如 if-then-else、cuts 等,但好处是:一旦你的数据被干净地表示出来,它就可以通过整个(大)余数的模式匹配*排他地*处理。你的程序!您正在标记您的数据,而不是标签。 (4认同)