【问题标题】:How to call a predicate from another predicate in Prolog?如何从 Prolog 中的另一个谓词调用谓词?
【发布时间】:2014-03-13 09:15:29
【问题描述】:

所以我刚启动 Prolog,我想知道两件事:

1) 是否有内置函数(或者它们都称为谓词?)用于简单的事情,例如最多 2 个数字或一个数字的正弦等...如果是,我如何访问它们?

2) 如何调用另一个谓词?我写了两个谓词 car 和 cdr。 car 返回列表的头部,而 cdr 返回没有头部的列表。但现在我想在 cdr 上调用汽车。以下是一些澄清示例:

car([3,4,5,5], H). would return H = 3

cdr([3,4,5,5],L). would return L = [4,5,5]

我要问的是我该怎么做:

car(cdr[3,4,5,5]))

??

【问题讨论】:

  • car(cdr[3,4,5,5]),X) 然后 X 将包含您的答案,这不是返回值的数学函数,您需要阅读更多关于 prolog 的工作原理或学习的一个好方法是使用调试器并逐步观察代码运行,eclipse 有一个可以工作的 prolog 插件。对于内置谓词,请检查您使用的 prolog 版本的文档
  • 设置 Eclipse 以在 Prolog 上工作可能真的很痛苦...请考虑从更简单的东西开始,例如 大多数 Prolog 提供的交互式循环。

标签: prolog


【解决方案1】:

正如其他人所指出的,Prolog 中的 谓词 之所以这样称呼是有原因的:它们实际上不是 函数。许多 Prolog 新手开始尝试将他们知道的其他语言的功能映射到 Prolog,但通常会失败。 Prolog 是一种与大多数其他语言非常不同的编程工具。所以这有点像用了很长时间的各种锤子,然后有人递给你一个扳手,你想知道为什么它不能成为一把好锤子。

在 Prolog 中,谓词 是一种在实体之间声明关系 的方法。如果您说foo(a, b),则表示ab 之间存在称为foo 的关系。您可能已经看过这些示例:knows(joe, jim).knows(jim, sally). 您可以定义关系,例如:

remotely_acquainted(X, Y) :- knows(X, Z), knows(Z, Y), \+ knows(X, Y).

或者类似的东西。

谓词不返回值。它要么成功,要么失败。如果您有一系列用逗号分隔的谓词(“和”关系)并且Prolog遇到一个失败的谓词,它会备份(回溯)到最近的先前谓词,它可以通过其参数的不同实例化再次成功并移动再次前进。

为了增加一点混乱,Prolog 中有一些谓词是专门为计算算术表达式而设计的。这些行为类似于函数,但它们是特殊情况。例如:

X is Y / gcd(Z, 4).

这里,Z4 中的 gcd 被计算并返回其值,然后 Y 除以该值并将结果实例化为 X。还有各种其他函数,如max/2sin/1等,可以在文档中查找。

算术比较运算符也以这种方式运行(使用=:=/2>/2</2 等与数字表达式)。所以如果你说:

X < Y + Z

Prolog 将考虑对这些参数进行数值评估,然后对它们进行比较。

话虽如此,Prolog 确实允许嵌入术语结构。你可以有类似的东西:

car(cdr([1,2,3]))

作为一个术语。 Prolog 不会解释它。解释留给程序员。然后我可以创建一个谓词来定义这些术语的评估:

car([H|_], H).
cdr([_|T], T).

proc_list(car(X), Result) :-
    proc_list(X, R1),
    car(R1, Result), !.
proc_list(cdr(X), Result) :-
    proc_list(X, R1),
    cdr(R1, Result), !.
proc_list(X, X).

上述条款中的删减可防止在我不想要时回溯到proc_list(X, X)

然后:

| ?- proc_list(car(cdr([1,2,3])), R).

R = 2

yes
| ?- proc_list(car(cdr(cdr([1,2,3]))), R).

R = 3

yes
| ?-

请注意,这是一个简单的案例,我可能没有掌握正确排列carcdr 的所有细节。也可以使用=..call 等代替参数中的离散项carcdr 使其更通用。例如,更通用的proc_list 可能是:

proc_list(Term, Result) :-
    Term =.. [Proc, X],               % Assumes terms have just one argument
    member(Proc, [car, cdr]),         % True only on recognized terms
    proc_list(X, R1),                 % Recursively process embedded term
    ProcCall =.. [Proc, R1, Result],  % Construct a calling term with Result
    call(ProcCall), !.
proc_list(X, X).

这种处理术语的技术确实远离了 Prolog 最擅长的关系行为,并倾向于功能行为,但要了解 Prolog 的工作原理。

【讨论】:

    【解决方案2】:

    Prolog 对计算的态度真的不同...

    您不定义函数,而是定义参数之间的关系。我所知道的最相似和最知名的语言是 SQL。将谓词视为表(或存储过程,当需要一些数据库引擎未预定义的计算时)。

    car([H|_],H).
    cdr([_|T],T).
    
    car_of_cdr(L, Car) :- cdr(L, Cdr), car(Cdr, Car).
    

    但由于列表的语法是该语言的核心部分,因此更好的定义可能是

    car_of_cdr([_,X|_], X).
    

    无论如何,我认为你应该花一些时间在一些 Prolog 教程上。 SO info page 有更多信息...

    【讨论】:

    • 其实可以在Prolog中定义函数的。 func library 为函数调用提供了更方便的语法。
    • @AndersonGreen:好吧,我编写了自己的界面(参见lifterthis related comment),所以我可以建议你......这种语法糖化的快捷方式有缺点......跨度>
    【解决方案3】:
    :- use_module(support).
    

    这意味着模块将使用其他模块中编写的谓词。

    <module_name>:<predicate_name>(<atoms / Variables>).
    

    这样您就可以在另一个模块中调用谓词。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多