Как использовать foreach в SWI-Prolog - PullRequest
1 голос
/ 10 апреля 2011

Я хочу преобразовать список пар в два списка - первый, содержащий первые элементы пар, второй, содержащий вторые элементы пар.1006 *

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 ]

1 голос
/ 02 апреля 2017

Используя 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'].

Обратите внимание, что это расширенное решение. Во-первых, знакомство с основными рекурсивными решениями (представленными другими ответами) действительно полезно, и я рекомендую его. Без хорошего понимания рекурсии, Пролог - просто один большой ад. На самом деле maplist тоже использует рекурсию, она просто скрыта от вызывающей стороны.

Еще одна вещь, которую нужно изучить, - это как работают термины Пролог и объединение.

  • Использование append здесь совершенно не нужно. Кроме того, это вредно как с точки зрения производительности, так и с точки зрения читаемости.
  • Пары лучше представить с помощью функтора, например, пара ['Test1', 'US'] становится pair('Test1', 'US'). Среди других преимуществ, сложнее случайно смешать пары и тройки. Использование функторов несколько похоже на использование типов в других языках.

    SWI-Prolog использует дефис-минус в качестве функтора для пар . Благодаря объявлению оператора дефис-минус также может использоваться в инфиксной нотации. Например. пара ['Test1', 'US'] становится 'Test1'-'US'. Инфиксная нотация является просто синтаксическим сахаром для обычной префиксной нотации, используемой для других функторов (т.е. 'Test1'-'US' == -('Test1', 'US')).

Наконец, нотация foreach ... do, которую вы пытались использовать, выглядит как циклическая конструкция из ECLiPSe , которая является производным от Prolog. SWI-Prolog не поддерживает этот синтаксис.

1 голос
/ 10 апреля 2011
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-B или pair(A, B).
  2. append([A], L1, L2) совпадает с L2 = [A | L1], последний более читабелен.
1 голос
/ 10 апреля 2011

Хорошо

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'].
0 голосов
/ 23 ноября 2012
testfor([], [], []).
testfor([[X, Y]|T1], [X|T2], [Y|T3]):-testfor(T1, T2, T3).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...