【问题标题】:How can I use a functor name like a variable in Prolog?如何在 Prolog 中使用函子名称,如变量?
【发布时间】:2014-06-10 08:59:21
【问题描述】:

我们的 Prolog 课程有这个作业。经过两个月每周一小时的 Prolog,这对我来说仍然是一个谜,我的思维似乎无法适应程序语言。

有一个知识库,其中包含具有相同名称的谓词/函子和元数 1、2 和 3。 调用形式应该是

搜索(函子名称,参数,S)。

无论元数如何,答案都应该找到具有此函子名称和参数的所有事件。 答案应采用以下形式:

S = functor_name(argument);
S = functor_name(argument,_);
S = functor_name(_,argument);
S = functor_name(argument,_,_);
S = functor_name(_,argument,_);
S = functor_name(_,_,argument);
false.

我发现我可以使用 call 来测试知识库中的条目是否存在。

但是 call 似乎不适用于函子名称的变量。我完全感到困惑,不知道如何使用变量作为仿函数名称。

更新:

我的问题已部分回答。 我的新代码给出了 1、2 和 3 的真假(见下文)。

search(Person,Predicate) :-
   ID = Person, Key = Predicate, current_functor(Key,1),
   call(Key,ID)
 ; ID = Person, Key = Predicate, current_functor(Key,2),
   (call(Key,ID,_);call(Key,_,ID))
 ; ID = Person, Key = Predicate, current_functor(Key,3),
   (call(Key,ID,_,_);call(Key,_,ID,_);call(Key,_,_,ID)).

更新2:

另一个部分答案出现了。那个给我 S 作为术语列表,但“其他”参数是占位符:

search2(Predicate, Arg, S) :-
   ( Arity = 2 ; Arity = 3 ; Arity = 4 ),
   functor(S, Predicate, Arity),
   S =.. [_,Predicate|Args],
   member(Arg, Args).

结果非常好。仍然缺少:谓词不应该在括号内,其他参数应该从知识库中直接获取,而不是写成占位符。当前结果如下所示:

 ?- search2(parent,lars,S).
S = parent(parent, lars) ;
S = parent(parent, lars, _G1575) ;
S = parent(parent, _G1574, lars) ;
S = parent(parent, lars, _G1575, _G1576) ;
S = parent(parent, _G1574, lars, _G1576) ;
S = parent(parent, _G1574, _G1575, lars).

我放弃了这个问题,因为这个问题从一开始就以错误的方式提出。我应该更具体地问 - 我不能,因为我仍然不擅长 Prolog。

@false 对我帮助最大。我接受他的回答。

【问题讨论】:

  • -1 用于在收到答案后添加一个额外的、不相关的问题。已经有很多关于收集结果的问题。
  • 那么,如果我没有找到答案,我宁愿写一个新问题吗?
  • 如果您的原始问题得到回答,您应该接受最合适的答案,如果您有新问题,请发布新问题。在您认为可以接受之前,您不应将单个 SO 问题用作后续问题流。这不是论坛主题。它应该是(1)问一个具体的技术问题,(2)得到具体的答案。新问题需要单独发布。
  • 好的,我的问题不好——太复杂了。我们甚至没有接近我想要的。我现在有两个部分答案需要合并。无论我接受哪一个,我都会对对方刻薄。 :(
  • 如果 SO 允许您投票,即使您不能接受一个完整的答案,您也可以投票给每个有用的答案。

标签: variables prolog functor meta-predicate


【解决方案1】:

这里有两种方法,一种是“传统”(1970 年代),可以实现您想要的:

search(F, Arg, S) :-
   ( N = 1 ; N = 2 ; N = 3 ), % more compactly: between(1,3, N)
   functor(S, F, N),
   S =.. [_|Args],            % more compactly: between(1,N, I), arg(I,S,Arg)
   member(Arg, Args).

另一位则重新考虑目标的明确构造。实际上,如果你有一个函子F,和参数A1A2A3,你可以立即编写目标call(F, A1, A2, A3),而无需使用functor/3(=..)/2

使用call(F, A1, A2, A3) 代替Goal =.. [F, A1, A2, A3], call(Goal) 有很多优点:在许多情况下,它更干净、更快,并且更容易进行类型检查。此外,当使用模块系统时,F 的潜在模块资格的处理将无缝工作。而(=..)/2 将不得不明确地处理所有丑陋的细节,那就是更多的代码,更多的错误。

search(F,A,call(F,A)).
search(F,A,call(F,A,_)).
search(F,A,call(F,_,A)).
search(F,A,call(F,A,_,_)).
search(F,A,call(F,_,A,_)).
search(F,A,call(F,_,_,A)).

如果你想缩短这个,不如动态构造call/N

search(F, Arg, S) :-
   ( N = 2 ; N = 3 ; N = 4 ),
   functor(S, call, N),
   S =.. [_,F|Args],
   member(Arg, Args).

请注意,调用需要为函子 F 提供额外参数!

【讨论】:

  • 最后一个例子给了我一个格式列表“S = call(parent, ...最多三个其他的东西,其中之一是参数)”。输出中的其他内容是占位符 _Gxxxx。我想要的是知识库中的每个条目,其中包含不相关的谓词及其参数之一的参数。然后,每个条目的列表以及其他参数,如“jon”、“margret”等。所有其他同事都放弃了,诅咒 Prolog。问题是,我几乎看不懂代码示例。每当我更改任何内容以使其按我想要的方式工作时,编译都会失败。
  • @AOphagen:这个例子不一定是最好的开始。但是
  • @AOphagen:你可能想要search(F, Arg) :- current_predicate(F/N), functor(Goal, F, N), between(1,N, I), arg(I,Goal,Arg), call(Goal).,但不是很清楚。
  • 呃,感谢您的持续帮助。是的,这看起来好像需要一段时间才能运行。统一是我绝对不明白的。我会玩一点,看看会发生什么。顺便说一句,老师现在任何一年都会退休,他可能正在寻找一些你可能会发现遗留方法的东西。
【解决方案2】:

您可以使用“univ”运算符=.. 动态构建目标:

?- F=member, X=1, L=[1,2,3], Goal =.. [F, X, L], call(Goal).
F = member,
X = 1,
L = [1, 2, 3],
Goal = member(1, [1, 2, 3]) .

【讨论】:

  • call(F, X, L)替换Goal =.. [F, X, L], call(Goal)
  • 是的,我知道。我的问题是我也不明白如何使用。但有一些进展。 23 ?- F=父母,X=hans,呼叫(F,X)。 F = 父母,X = 汉斯。快乐的。 (种类)
  • 由于您的参数列表不固定,您可能希望使用apply/2 而不是call/2
  • @TudorBerariu: apply/2 绝对是最糟糕的:它不进行类型检查,而且天生效率低下,许多系统不再支持。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多