web-dev-qa-db-fra.com

Comment ajouter un élément à une liste en place dans Prolog?

Si j'ai une liste dans Prolog telle que X = [1, 2, 3, 4], comment ajouter l'élément 5 à la fin de la liste pour avoir X = [1, 2, 3, 4, 5]?

La fonction append a besoin de deux listes, c'est-à-dire append (A, B, C) pour obtenir A et B concaténés à la liste C.

Je peux le faire avec une liste temporaire Y = [1, 2, 3, 4] et Z = [5], pour ensuite faire un ajout (Y, Z, X), mais je n'aime pas avoir une liste temporaire.

Les exclusions habituelles s'appliquent ici - ce ne sont pas des devoirs et j'apprends juste Prolog.

18
No One in Particular

Les variables dans Prolog ne peuvent être attribuées qu'une seule fois. Dès que X a la valeur [1,2,3,4], il ne peut jamais avoir une autre valeur. Une variable temporaire et append/3, comme vous l'avez mentionné, est la façon de le faire.

Cela dit, vous pouvez faire une astuce qui n'est probablement pas recommandée. Si X = [1,2,3,4, Y] alors vous pouvez faire Y = 5 et X a maintenant la valeur souhaitée. Je crois que cette technique s'appelle une liste de différences.

6
mndrix

Comme les autres l'ont souligné, vous allez être coincé avec le problème de performance.
Mais juste comme exercice, j'ai décidé d'essayer de créer un prédicat qui pourrait ajouter un élément à la fin d'une liste, sans utiliser append.

% add_tail(+List,+Element,-List)
% Add the given element to the end of the list, without using the "append" predicate.
add_tail([],X,[X]).
add_tail([H|T],X,[H|L]):-add_tail(T,X,L).

Je conseillerais que vous utilisiez simplement la fonction append, en tant que fonction intégrée, elle sera probablement plus rapide que tout ce qui est conçu manuellement.

7
S.L. Barth

Une solution déclarative consiste à utiliser une liste de différences (comme Daniel l'a suggéré dans sa réponse). Une liste de différences tire son nom d'être généralement représentée comme une différence entre deux listes: une liste et sa queue. Par exemple, une liste vide peut être représentée par T-T. Une liste avec les éléments 1, 2 et 3 peut être représentée par [1,2,3| T]-T (Notez que (-)/2 est l'opérateur d'infixe intégré standard). L'avantage de cette représentation est que vous pouvez ajouter un élément à une liste en temps constant en utilisant une définition de fait unique de append/3 prédicat:

append(L1-T1, T1-T2, L1-T2).

Un exemple d'utilisation:

?- append([1,2,3,4| T1]-T1, [5| T2]-T2, Result).
T1 = [5|T2],
Result = [1, 2, 3, 4, 5|T2]-T2.

Si nécessaire, il n'est pas difficile de convertir entre une liste "normale" et une liste de différences. Je vous laisse cela comme un exercice.

3
Paulo Moura

Vous vous inquiétez de la mauvaise fin du problème. Le partage de structure ne peut se produire qu'en mettant un élément au début de la liste. Cette méthode a les caractéristiques de performance que vous souhaitez. En raison de la façon dont les listes sont définies, lorsque vous ajoutez deux listes, la première liste entière est copiée. Dans ce cas, ce sera toute la liste. Les déchets générés par une liste à un élément vont évidemment être beaucoup plus petits que cela.

Si vous devez vraiment ajouter, envisagez de construire la liste en arrière puis de l'inverser une fois à la fin, ce qui est beaucoup moins cher, ou utilisez des listes de différences, qui permettent une ajout efficace à la fin.

2
Daniel Lyons

Vous ne pouvez pas modifier des listes dans Prolog, mais vous pouvez créer une liste avec une longueur non spécifiée:

main :-
    A = [1,2,3,4|_].

Ensuite, vous pouvez insérer un élément à l'aide de nth0/3 dans SWI-Prolog:

:- initialization(main).

main :-
    A = [1,2,3,4|_],
    nth0(4,A,5),
    writeln(A).

Une fois cet élément inséré, A = [1,2,3,4,5|_].

Vous pouvez également définir une fonction qui ajoute un élément à la fin d'une liste sur place, puis l'utiliser comme ceci:

:- initialization(main).

append_to_list(List,Item) :-
    List = [Start|[To_add|Rest]],
    nonvar(Start),
    (var(To_add),To_add=Item;append_to_list([To_add|Rest],Item)).

main :-
    A = [1,2,3|_],
    append_to_list(A,4),
    append_to_list(A,4),
    writeln(A).

Dans cet exemple, A = [1,2,3,4,4|_] après l'ajout de ces deux éléments.

2
Anderson Green

Puisque Prolog a ajouté qui n'accepte que des listes, pourquoi ne l'utilisons-nous pas pour insérer notre élément dans l'une des listes. c'est à dire.

% E = element, L = list, R = result
% e.g. add_elem_in_list ([1,2,3,4], 5, R).
add_elem_in_list(L, E, R) :- append(L, [E], R).
1
Imam Bux