所以我刚开始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]
Run Code Online (Sandbox Code Playgroud)
而我要问的是我该怎么做:
car(cdr[3,4,5,5]))
Run Code Online (Sandbox Code Playgroud)
??
lur*_*ker 10
正如其他人所指出的那样,Prolog中的谓词被称为出于某种原因:它们实际上不是函数.Prolog的许多新手开始试图将他们熟悉的其他语言功能映射到Prolog,但它通常都失败了.Prolog是一种与大多数其他语言截然不同的编程工具.所以这有点像使用各种锤子很长一段时间,然后有人给你扳手,你想知道为什么它不能成为一把好锤子.
在Prolog中,谓词是一种声明实体之间关系的方法.如果你说它foo(a, b)
意味着它之间存在关系a
并且b
被称为foo
.你可能看到的例子:knows(joe, jim).
和knows(jim, sally).
您可以定义的关系,如:
remotely_acquainted(X, Y) :- knows(X, Z), knows(Z, Y), \+ knows(X, Y).
Run Code Online (Sandbox Code Playgroud)
或类似的东西.
一个谓词没有返回值.它要么成功要么失败.如果你有一个用逗号分隔的谓词序列(一个"和"关系)并且Prolog遇到一个失败的谓词,它会备份(回溯)到最近的先前谓词,它可以通过不同的参数实例化和移动再次成功再次前进.
只是为了增加一点混乱,Prolog中有一些专门用于评估算术表达式的谓词.这些功能就像功能一样,但它们都是特例.例如:
X is Y / gcd(Z, 4).
Run Code Online (Sandbox Code Playgroud)
在这里,gcd
中Z
和4
计算的其返回值,然后Y
由该值分割的结果实例化为X.有各种各样的其它功能,如max/2
,sin/1
等你可以看看他们的文档中.
算术比较运算符起作用这种方式,以及(使用=:=/2
,>/2
,</2
等用数字表达式).所以,如果你说:
X < Y + Z
Run Code Online (Sandbox Code Playgroud)
Prolog将考虑对这些论点进行数值评估,然后对它们进行比较.
所以尽管如此,Prolog确实允许嵌入术语结构.你可以有类似的东西:
car(cdr([1,2,3]))
Run Code Online (Sandbox Code Playgroud)
作为一个术语.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).
Run Code Online (Sandbox Code Playgroud)
上面条款中的切入可以防止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
| ?-
Run Code Online (Sandbox Code Playgroud)
请注意,这是一个简单的案例,我可能没有捕捉到做正确序列car
和的所有微妙之处cdr
.它也可以更通用地使用=..
和call
等,而不是离散的术语car
和cdr
参数.例如,稍微更一般的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).
Run Code Online (Sandbox Code Playgroud)
这种处理术语的技术确实远离了Prolog最擅长的关系行为,并且倾向于功能行为,但是要理解Prolog的工作原理.