我正在学习Prolog,我看到了这段代码
foo([],[]).
foo([[A,_ ]|L], [A|P]) :-foo(L ,P).
结果表明该代码取列表的N个元素, 广告示例,如果我们给出以下查询:
?foo([[car],[house],[man]],X)
X= [c,h,m]
初读时我发现有问题。 对我来说,这段代码采用list列表的尾部和list的第一个元素的其余部分,因此对我来说,第一个扩展将是(trace)
foo([[house],[man]], ar)
foo([[man]], ouse)
foo([], an)
false.
我尝试使用swi-prolog进行编译并给出以下跟踪信息:
[trace] ?- trace,foo([[car],[house],[man]],X).
Call: (9) foo([[car], [house], [man]], _1016) ? creep
Fail: (9) foo([[car], [house], [man]], _1016) ? creep
false.
我怎么了?
答案 0 :(得分:2)
您的子句中的模式[A, _]
错误,或者至少不够通用。 [A, _]
通过一个包含恰好两个元素的列表来统一,但是对于包含两个以上元素或一个元素的列表(如您所发现的),这将失败。
您需要使用[A|_]
模式:确实是列表,其中头是A
,而我们对其余的(尾部)不感兴趣。喜欢:
foo([],[]).
foo([[A|_]|L], [A|P]) :- foo(L, P).
话虽如此,您可以通过实现采用列表头的谓词来简化此过程:
head([H|_], H).
,然后使用maplist/3
[swi-doc]:
foo(A, B) :-
maplist(head, A, B).
因此, maplist
将像head
那样调用head(Ai, Bi)
,分别使用Ai
和Bi
的{{1}}和A
个元素。
但是基于示例输出,这不是您想要的:您还想获取原子的第一个“字符”,我们可以使用string_chars/2
[swi-doc]来做到这一点:
B
,然后再次用maplist/3
[swi-doc]定义head_first([A|_], C) :-
string_chars(A, [C|_]).
:
foo/2
然后我们获得:
foo(A, B) :-
maplist(head_first, A, B).