2017-01-11 1 views
1

Quand j'écrivais this question on an empty list as a difference list je voulais tester ce que je savais au sujet de ces structures. Cependant, quand j'ai essayé quelque chose d'aussi simple que de comparer différentes notations, il m'a semblé que j'avais tort et que je n'ai pas compris ce qui se passe réellement avec les listes de différence. Je l'ai testé sur SWI-Prolog ainsi que sur SICStus. J'ai vérifié la notation car c'est ainsi qu'elle est écrite dans la programmation Prolog de Bratko pour l'IA, page 210, mais apparemment l'unification n'est pas possible. Pourquoi donc? Ces notations n'ont-elles pas le même sens déclaratif?Comment utiliser des listes de différence dans un interpréteur Prolog

+2

La clé pour lire cette section est le mot * représente *. Si vous regardez dans le livre, quand les exemples peuvent être utilisés avec le niveau supérieur, l'interpréteur AKA, ils sont préfixés avec '? -'. Dans cette section, on lit 'Ainsi, la liste [a, b, c] peut être représentée, par exemple, par [a, b, c] - [] ou [a, b, c, d, e] - [d, e] ou [a, b, c, d, e | T] - [d, e | T] ou [a, b, c | T] -T où T est une liste. »Ce n'est donc pas un exemple courir avec le niveau supérieur, mais des exemples qui * représentent * ce que vous devriez penser, donc l'erreur lors de l'utilisation comme entrée dans le niveau supérieur. –

+1

'L' ne peut pas être' '[a, b, c | [d, e]] - [d, e]' et '[a, b, c]'. Ce sont deux structures différentes. – lurker

+0

@lurker Je vois cela maintenant, mais comme précisé dans les commentaires c'est probablement pourquoi je ne vois pas l'avantage pratique de la liste de différence. Vous aurez toujours besoin de l'étape * finalize * comme suggéré par Willem Van Onsem si vous voulez utiliser la liste concaténée. –

Répondre

3

Je pense que vous avez l'idée que l'interprète Prolog traite des listes de différence comme quelque chose de spécial. Ce n'est pas le cas: Prolog n'est pas au courant du concept d'une liste de différence (ni de presque tous les concepts sauf certains sucre syntactique). Il ne voit que:

L=-(|(a, |(b, |(c, |(d, |(e, []))))), |(d, |(e, []))) 

-/2 et |/2 sont foncteurs et a, b, c, d, e et [] sont des constantes.

listes de différence sont tout simplement une technique de programmation (comme par exemple programmation dynamique est une technique aussi bien, le compilateur ne peut détecter ni traiter différemment les programmes de programmation dynamique). Il est utilisé pour unifier efficacement une partie (partiellement) non unifiée au plus profond d'une expression.

que vous voulez append/3 deux listes. Vous pouvez le faire comme suit:

%append(A,B,C). 
append([],L,L). 
append([H|T],L,[H|B]) :- 
    append(T,L,B). 

Mais cela va dans O (n): vous devez d'abord parcourir la liste complète en premier. Si cette liste contient des milliers d'éléments, cela prendra beaucoup de temps.

Maintenant, vous pouvez définir vous un contrat que vous nourrir un append_diff/3 non seulement la liste, mais un tuple -(List,Tail)List est une référence au début de la liste, et Tail est une référence à la fin de la liste non unifiée. Des exemples de structures qui satisfont à cette exigence sont Tail-Tail, [a|Tail]-Tail, [1,4,2,5|Tail]-Tail.

Maintenant, vous pouvez effectivement append_diff/3 à O (1) avec:

append_diff(H1-T1,T1-T2,H1-T2). 

Pourquoi? Parce que vous unifier la queue non unifiée de la première liste avec la deuxième liste. Maintenant, la queue non unifiée des deuxièmes listes devient la queue de la liste finale.Alors, prenez par exemple:

append_diff([a|T1]-T1,[1,4,2,5|T2]-T2,L). 

Si vous appelez le prédicat, comme vous le voyez ci-dessus, T1 unifierons avec [1,4,2,5|T2], maintenant la première liste se réduit à [a|[1,4,2,5|T2]] ou moins [a,1,4,2,5|T2], puisque nous avons aussi une référence à T2, nous pouvons "retourner" (dans Prolog rien n'est retourné), [a,1,4,2,5|T2]-T2: une nouvelle liste de différence avec une queue ouverte T2. Mais cela est seulement parce que vous donnez - vous-même signification particulière: pour Prolog - est tout simplement -, ce n'est pas moins , il ne calcule pas une différence, etc. Prolog ne pas attacher la sémantique à foncteurs. Si vous aviez utilisé + au lieu de -, cela n'aurait pas fait la moindre différence. Donc, pour revenir à votre question: vous dites simplement à Prolog que L = -([a,b,c,d,e],[d,e]) et plus tard, vous dites L = [a,b,c]. Maintenant, il est clair que ces deux expressions ne peuvent pas être unifiées. Donc, Prolog dit false.

+0

Je comprends maintenant pourquoi ils ne unifient pas, mais je ne comprends pas comment append_diff/3 serait utile dans la pratique. Je veux dire, si c'est comme ça que vous faites, le résultat serait '[a, 1,4,2,5 | T2] -T2'. Vous n'avez toujours pas la valeur que vous voulez, c'est-à-dire '[a, 1,4,2,5]', n'est-ce pas? –

+0

@BramVanroy: bien vous pouvez définir un prédicat 'finalize (A - [], A). 'Qui" finalise "la liste de diff. Si vous appelez alors 'finalize ([a, 1,4,2,5 | T2] -T2, Result).' Result' sera '[a, 1,4,2,5]'. Mais comme dit précédemment, tout dépend de la façon dont vous interprétez vous-même les données. Vous pouvez interpréter '[a, 1,4,2,5 | T2] -T2' comme une liste * équivalente * à' [a, 1,4,2,5] '. –

+0

Mais Prolog n'interprète pas la structure comme ça, donc l'étape 'finalize/2' serait nécessaire pour avoir une liste concaténée, non? (À la suite d'un commentaire publié sur une autre question.) À titre d'exemple, nous voulons ajouter [a, b] et [c, d]. Solution proposée: 'conc_d ([a, b | T] -T, [d, e | T1] -T1, L). Cependant, le résultat serait' L = [a, b, c, d | T1] -T1', mais en tant que programmeur, j'aurais besoin de '[a, b, c, d]', simple et clair. J'ai le sentiment que je ne comprends pas, mais je ne vois pas l'avantage pratique ou je ne vois pas comment utiliser les listes de différences dans la pratique. –