2016-04-21 7 views
5

Angenommen, ich möchte Ganzzahlen wie folgt darstellen: integer:Sign:[FirstDigit,SecondDigit,...]. Zum Beispiel würde 42 als integer:positive:[4,2] dargestellt werden.Liste der Ganzzahlen und Endlosschleife in Prolog CLPFD

Ich brauche ein Prädikat, das den Wert der ganzen Zahl basierend auf dieser Darstellung erzeugt und umgekehrt.

Hier ist, was ich kam mit:

integer_value_('integer':Sign:[H],E) :- 
    H in 0..9, 
    (
     Sign = 'positive', 
     E #= H 
     ; 
     Sign = 'negative', 
     E #= -H 
    ). 
integer_value_('integer':Sign:[H,I|T],E) :- 
    H in 0..9, 
    length([I|T],L), 
    (
     Sign = 'positive', 
     E #= F + H * 10^L 
     ; 
     Sign = 'negative', 
     E #= F - H * 10^L 
    ), 
    integer_value_('integer':Sign:[I|T],F). 

Dies funktioniert wie erwartet. Es hat jedoch die unglückliche Eigenschaft, Dinge wie integer:positive:[0,1] zu akzeptieren, dh führende Nullen am Anfang der Liste. Dies ist besonders problematisch, wenn ich alle möglichen Ganzzahlen mit integer_value_(I,J), label([J]). aufzählen: die mit führenden Nullen erscheinen auch.

ich dann versucht, dies zu korrigieren, indem Sie integer_value_ nur für alle, aber die erste Stelle, und integer_value für die erste Verwendung (unter Berücksichtigung der Tatsache, dass wir für 0 werden mit einer Liste dargestellt, die nur 0 empfangen müssen):

integer_value('integer':Sign:[H],E) :- 
    abs(E) #< 10, 
    abs(E) #> -1, 
    integer_value_('integer':Sign:[H],E). 
integer_value('integer':Sign:[H,I|T],E) :- 
    H in 1..9, 
    length([I|T],L), 
    (
     Sign = 'positive', 
     E #= F + H * 10^L 
     ; 
     Sign = 'negative', 
     E #= F - H * 10^L 
    ), 
    integer_value_('integer':Sign:[I|T],F). 

Allerdings verhält es sich jetzt nicht richtig. Zum Beispiel gibt integer_value(I,-19).I = integer:negative:[1, 9] zurück, aber wenn wir nach einer anderen Antwort fragen, geht Prolog aus Gründen, die ich nicht verstehe, in eine Endlosschleife (es sollte falsch sein oder bereits wissen, dass es keine anderen Antworten gibt).

Dieses Problem nicht mit der „gegenüberliegenden“ -Abfrage auftritt integer_value(integer:negative:[1,9],Z). die Z = 19 und dann false zurück, auch nicht auftreten, wenn beide Argumente Variablen sind (es aufzählt Zahlen richtig, ohne führende Nullen), die mir überraschend.

Irgendeine Idee, was diese Endlosschleife auftritt, und wenn es eine einfache Möglichkeit gibt, es zu beheben?

+0

+1 für einen sehr interessanten und geeigneten Anwendungsfall von CLP (FD) Einschränkungen! Ich habe einen kleinen Kommentar zu den einzelnen Anführungszeichen: Sie können das '' 'für alle Atome weglassen, die keine solchen Anführungszeichen benötigen, wie 'positiv', 'negativ', 'ganzzahlig' usw. Sie können diese Atome einfach direkt niederschreiben wie "Vorzeichen = positiv", "Vorzeichen = negativ" und "Ganzzahl: Vorzeichen: [I | T]". – mat

+0

@mat Ich weiß, aber da ich kein Prolog-Programmierer bin, finde ich es ziemlich hässlich, solche Atome zu haben: p – Fatalize

Antwort

5

Um das Problem zu sehen, ist es ausreichend, einen winzigen Bruchteil Ihres Programms zu betrachten. In der Tat ist die folgende ausreichend:

 
integer_value('integer':Sign:[H],E) :- false, 
    abs(E) #< 10, 
    abs(E) #> -1, 
    integer_value_('integer':Sign:[H],E). 
integer_value('integer':Sign:[H,I|T],E) :- 
    H in 1..9, 
    length([I|T],L), false, 
    ( Sign = 'positive', 
     E #= F + H * 10^L 
     ; 
     Sign = 'negative', 
     E #= F - H * 10^L 
    ), 
    integer_value_('integer':Sign:[I|T],F). 

L tritt hier zum ersten Mal, so dass jede Länge möglich ist. Sie müssen das Längenziel irgendwie ändern.

+1

Vergiss es, ich habe es. Jetzt um es zu lösen ... – Fatalize

+2

@Fatalize: Siehe [dies] (http://Stackoverflow.com/a/28442760/772868) für ein verwandtes Problem. – false

3

konnte ich mein Problem lösen indem this other answer von @False

Einer der Fang wies darauf hin, ist von dem Vorzeichen der Zahl als letzten Schritt zu entscheiden, so dass, wenn durch mögliche ganze Zahlen iterieren wir abwechselnd Antworten erhalten zwischen positiven und negativen Zahlen: nach Erreichen von 9 (1 Ziffer), wird es mit -9, dann -8 usw. vereinheitlichen. Nach -1 wird es mit 10, 11, etc. vereinheitlichen. Nach 99 wird es mit -99 vereinheitlichen , -98, usw. Sie bekommen den Punkt.

integer_value('integer':Sign:I,E) :- 
    integer_value('integer':Sign:I,0,E,E). 

integer_value('integer':Sign:[H],N0,N,M) :- 
    H in 0..9, 
    N1 #= H + N0 * 10, 
    abs(M) #>= abs(N1), 
    integer_value_('integer':Sign:[],N1,N,M). 
integer_value('integer':Sign:[H,I|T],N0,N,M) :- 
    H in 1..9, 
    N1 #= H + N0 * 10, 
    abs(M) #>= abs(N1), 
    integer_value_('integer':Sign:[I|T],N1,N,M). 

integer_value_('integer':Sign:[],N0,N,_) :- 
    (
     Sign = 'positive', 
     N #= N0 
     ; 
     Sign = 'negative', 
     N #\= 0, 
     N #= - N0 
    ). 
integer_value_('integer':Sign:[H],N0,N,M) :- 
    H in 0..9, 
    N1 #= H + N0 * 10, 
    abs(M) #>= abs(N1), 
    integer_value_('integer':Sign:[],N1,N,M). 
integer_value_('integer':Sign:[H,I|T],N0,N,M) :- 
    H in 0..9, 
    N1 #= H + N0 * 10, 
    abs(M) #>= abs(N1), 
    integer_value_('integer':Sign:[I|T],N1,N,M).