术语列表的术语扩展

时间:2014-08-08 12:08:36

标签: macros prolog

说我希望有一些规则都遵循相同的模式。当我想通过显式列出所有可能的第一个参数来避免非确定性行为时,我遇到了这种情况。但是,我知道,我需要为某些可能性做同样的事情。处理它的一种方法是在最后有一个包罗万象的条款:

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

但这不是很好,因为我实际上无法知道是否有意外输入,或者我在程序中犯了错误。为了避免这种情况,我也可以说

foo(X) :- memberchk(X, [ /* list of possible values of X */ ]).

但是,再一次,我现在正在反对Prolog的确定性行为和索引,当争论开始时。

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

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 (在最底部)

1 个答案:

答案 0 :(得分:3)

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

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

这个问题的主要问题是最后一个条款(foo(_))适用于另一个 - 可能是更专业的 - 条款也适用。因此,查询?- foo(a).现在无意中是非确定性的。

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

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

当术语出现意外形式时,会引发错误。我使用xy作为未经特殊处理的条款的示例。请注意,当然必须包含ab,因为该条款(同样)也适用于它们。即使它的参数被实例化,谓词仍然不是确定性的,因为第一个参数索引不能区分这些情况。你写道:“我现在正在反对Prolog的确定性行为,并在争论开始时编制索引”,并且可能(并且正确地)意味着当您使用此表示时,您无法从这些功能中受益。

现在很好的声明性解决方案:每当你想要引入“全能”或“默认”条款时,重新考虑你的数据表示,并为不同的情况引入区别的仿函数可以申请。在您的示例中,这两种情况是:

  1. 该术语需要以特殊方式处理
  2. 这个词没什么特别的。
  3. 我将使用special(_)ordinary(_)来区分这些案例。因此:

    foo(special(S)) :- foo_special(S).
    foo(ordinary(_)). % do nothing
    
    foo_special(a) :- /* do something      */
    foo_special(b) :- /* do something else */
    

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