如何在SWI-Prolog中使用foreach

时间:2011-04-10 14:46:24

标签: prolog

我想将对列表转换为两个列表 - 首先包含对的第一个元素,第二个包含对的第二个元素。

E.g。

[['Test1', 'US'], ['Test1', 'France'], ['Test2', 'German']]

应该产生

List1 = ['Test1', 'Test1', 'Test2']
List2 = ['US', 'France', 'German']

我尝试使用foreach并提出此功能:

testfor:-
List = [['Test1', 'US'], ['Test1', 'France'], ['Test2', 'German']],
(
  foreach(X,List) do
    X=[F,S],
    append([F],[],List1),
    append([S],[],List2)
),
writeln(List1).

它不起作用,我很困惑。我在哪里弄错了?当然,您可以使用您的方法帮助我实现此功能(即“不要使用foreach”)。

4 个答案:

答案 0 :(得分:1)

yoba( [], [], [] ).
yoba( [[Name1, Name2] | Tail], List1, List2 ) :-
    append( [Name1], ListNew1, List1 ),
    append( [Name2], ListNew2, List2 ),
    yoba( Tail, ListNew1, ListNew2 ).

?- yoba([['Test1', 'US'], ['Test1', 'France'], ['Test2', 'German']], X, Y).
X = ['Test1', 'Test1', 'Test2'],
Y = ['US', 'France', 'German'].

答案 1 :(得分:1)

pairs_to_lists([], [], []).

pairs_to_lists([E1-E2 | Tail], [E1 | Tail1], [E2 | Tail2]) :-
    pairs_to_lists(Tail, Tail1, Tail2).

用法:

?- pairs_to_lists(['Test1'-'US', 'Test1'-'France', 'Test2'-'German'], L1, L2).
L1 = ['Test1', 'Test1', 'Test2'],
L2 = ['US', 'France', 'German'].

一些意见:

  1. 如果您知道其中的元素数量,则列表是一种过度杀伤,例如:而不是[A, B]使用A-Bpair(A, B)
  2. append([A], L1, L2)L2 = [A | L1]相同,后者更具可读性。

答案 2 :(得分:1)

使用maplist/4,隐藏整个迭代,你必须考虑一对的解构。

%zip(?FirstList, ?SecondList, ?PairList)
zip(Fst, Snd, Pair) :- maplist(pair, Fst, Snd, Pair).

%pair(?First, ?Second, ?Pair)
pair(Fst, Snd, [Fst, Snd]).

因此使用它:

?- zip(List1, List2, [['Test1', 'US'], ['Test1', 'France'], ['Test2', 'German']]).
List1 = ['Test1', 'Test1', 'Test2'],
List2 = ['US', 'France', 'German'].

请注意,这是一个高级解决方案。首先,了解基本的递归解决方案(由其他答案提供)非常有用,我推荐它。没有很好地掌握递归,Prolog只是一个大地狱。实际上,maplist也使用递归,它只是从调用者隐藏。

要学习的另一件事是Prolog的术语和统一是如何运作的。

  • 此处完全没有必要使用append。此外,它在性能和可读性方面都是有害的。
  • 使用仿函数可以更好地表示对,例如对['Test1', 'US']变为pair('Test1', 'US')。除了其他好处之外,偶然混淆对和三胞胎更难。使用仿函数有点类似于使用其他语言的类型。

    SWI-Prolog使用连字符减号作为pairs的函子。由于具有operator declaration,连字符 - 减号也可用于中缀符号。例如。对['Test1', 'US']变为'Test1'-'US'。中缀表示法只是用于其他仿函数的通常前缀表示法的语法糖(即'Test1'-'US' == -('Test1', 'US'))。

最后,您尝试使用的foreach ... do符号看起来像loop construct from ECLiPSe,这是一种源自Prolog的语言。 SWI-Prolog不支持这种语法。

答案 3 :(得分:0)

testfor([], [], []).
testfor([[X, Y]|T1], [X|T2], [Y|T3]):-testfor(T1, T2, T3).