2014-09-11 6 views
3

Je fais une distance de prédicat/3 qui calcule la distance entre 2 points sur un plan 2D. Par exemple:Comment convertir (0,0) en [0,0] dans prolog?

?- distance((0,0), (3,4), X). 
X = 5 
Yes 

Mon prédicat ne fonctionne que si (0,0) est la liste [0,0]. Y a-t-il un moyen de faire cette conversion?

+1

Notez que '(0,0)' est une représentation plus compacte et efficace que '[0,0]'. C'est (plus) apparent lorsque vous regardez la représentation canonique des deux termes: '',' (0,0)' vs ''.' (0, '.' (0, []))'. Je suis curieux de savoir pourquoi votre prédicat ne peut fonctionner qu'avec une représentation de liste ... –

+0

Parce que j'utilise une division de la queue pour appliquer le théorème de Pythagore à (0,0) et (3,4). – Seb

+1

Mais vous n'avez pas besoin de faire un split tête-queue. Vous pouvez facilement extraire les valeurs de '(X, Y)'. 'distance ((X1, Y1), (X2, Y2), D): - D est sqrt ((X2-X1) * (X2-X1) + (Y2-Y1) * (Y2-Y1)).' Vous peut aussi définir 'square (X, S): - S est X * X.' si vous voulez. – lurker

Répondre

2

Vous pouvez le faire avec une règle simple qui unifie ses côtés gauche et droit:

convert((A,B), [A,B]). 

Demo.

+1

Merci, je dois le faire maintenant. Bien que j'ai le sentiment que je peux rendre mon programme un peu plus joli. Je vais travailler dessus :) – Seb

0

Si vous avez juste une paire simple, vous pouvez utiliser l'opérateur univ et simplement dire quelque chose comme:

X = (a,b) , 
X =.. [_|Y] . 

qui produit

X = (a,b) . 
Y = [a,b] . 

Cela ne fonctionne pas si X est quelque chose comme (a,b,c), la production comme il le fait

X = (a,b,c) . 
Y = [a,(b,c)] . 

[probablement pas ce que vous voulez].

Le cas le plus général est assez simple:

csv2list(X , [X] ) :- % We have a list of length 1 
    var(X) .     % - if X is UNbound 
csv2list(X , [X] ) :- % We have a list of length 1 
    nonvar(X) ,    % - if X is bound, and 
    X \= (_,_) .    % - X is not a (_,_) term. 
cs22list(Xs , [A|Ys]) :- % otherwise (the general case) , 
    nonvar(Xs) ,    % - if X is bound, and 
    Xs = (A,Bs) ,   % - X is a (_,) term, 
    csv2list(Bs,Ys   % - recurse down added the first item to result list. 
    .      % Easy! 
2

Bien que les autres ont répondu, gardez à l'esprit que (a,b) dans Prolog est en fait pas ce que vous pourriez penser qu'il est:

?- write_canonical((a,b)). 
','(a,b) 
true. 

Alors c'est le terme ','/2. Si vous travaillez avec des paires, vous pouvez faire deux choses qui sont probablement « plus joli »:

les garder comme une « paire », a-b:

?- write_canonical(a-b). 
-(a,b) 
true. 

L'avantage ici est que les paires comme cela peut être manipulé avec un groupe de prédicats standard de facto, par exemple keysort, ainsi que library(pairs). Ou, si elles sont en fait une structure de données qui fait partie de votre programme, vous pouvez aussi le rendre explicite, comme dans coor(a, b) par exemple. Une distance dans l'espace à deux dimensions alors prendre deux coor/2 termes:

distance(coor(X1, Y1), coor(X2, Y2), D) :- 
    D is sqrt((X1-X2)^2 + (Y1-Y2)^2). 

Si vous ne savez pas combien de dimensions que vous avez, vous pouvez en effet garder les coordonnées de chaque point dans une liste. Le message ici est que les listes sont destinées aux choses qui peuvent contenir 0 ou plusieurs éléments, alors que les paires, ou d'autres termes avec arité 2, ou tout terme avec une arité connue, sont plus explicites sur le nombre d'éléments qu'ils ont.

Questions connexes