2010-11-21 7 views
4

Mit SWI Prolog gibt es ein Prädikat, das das n-te Element in einer Liste namens nth1 findet. Ich möchte meine eigene Version des Prädikats implementieren, aber SWI's sind so kompliziert, wenn Sie sich den Listing (nth1) Code ansehen. Gibt es einen einfacheren Weg?Einfaches Prdikat nth1 in Prolog

Danke :).

+0

klären, was meinst du mit "einfacher"? Weniger Zeilen Code? Sie könnten z.B. "Listen: nth0_det (3, [_, _, _, A | _], A): -!." Ansonsten ist der einzige Weg, es einfacher zu machen, es weniger allgemein zu machen. Ist das was du willst? – Kaarel

Antwort

2

Der SWI-Code ist ein wenig kompliziert, weil das Prädikat aus einem variablen Index verwendet werden kann, generieren:

?- nth1(Idx,[a,b,c],X). 
Idx = 1, 
X = a ; 
Idx = 2, 
X = b ; 
Idx = 3, 
X = c ; 
false. 

Wenn Sie dieses Verhalten nicht wollen, nth1/3 leicht in Bezug auf nth0 umgesetzt werden kann:

nth1(Idx,List,X) :- 
    Idx0 is Idx-1, 
    nth0(Idx0,List,X). 

bearbeiten: es ist auch möglich, ohne nth0 in nur wenigen Zeilen Code zu tun:

nth1(1,[X|_],X) :- !. 
nth1(Idx,[_|List],X) :- 
    Idx > 1, 
    Idx1 is Idx-1, 
    nth1(Idx1,List,X). 
+0

Danke larsmans, ich möchte keine n-ten Prädikate verwenden, aber ich habe meine Lösung gepostet, was denkst du? Danke für die Post. – ale

+0

@shuyin, habe ich auch eine 'nth0'-lose Lösung gepostet. –

2

Ich wollte nicht widersprüchlich sein oder jemand anderen meine Arbeit tatsächlich tun; Ich wollte nur einen Rat, sorry dafür, dass ich nicht klarer bin.

Ich habe es jetzt selbst implementiert, aber könntest du vielleicht Verbesserungen oder bessere Möglichkeiten vorschlagen? Was ich oft in Prolog mache, ist ein Prädikat zu schreiben, indem man einen Zähler oder eine Menge von Zählern sagt und ein Prädikat mit weniger Argumenten erhält, um die Klauseln mit zusätzlichen Argumenten aufzurufen. Dies führt oft zu ziemlich viel Code. Wie auch immer, hier ist meine Implementierung, die ich gerade gemacht habe:

item_at(N, L, Item) :- 
    item_at(N, 0, L, Item). 
item_at(N, Count, [H|_], Item) :- 
    CountNew is Count + 1, 
    CountNew = N, 
    Item = H. 
item_at(N, Count, [_|T], Item) :- 
    CountNew is Count + 1, 
    item_at(N, CountNew, T, Item). 

Kommentare? Vielen Dank :). Verbrauch:

?- item_at(3,[a,b,c,d,e],Item). 
Item = c ; 
+0

+1, diese Version ist ziemlich allgemein (obwohl sie beim Zurückverfolgen/Erzeugen in unendliche Rekursion gehen könnte). Ein Vorschlag, die zweite Klausel kann viel kürzer sein: 'item_at (N, Count, [H | _], H): - N ist Count + 1.' –

+0

Danke larsmans, das ist eine schöne Verbesserung, vielen Dank dafür:). Getestet und funktioniert und ich kann sehen wie :). – ale

4

Betrachten endlichen Bereich Einschränkungen für die allgemeine (reversible) integer Arithmetik:

:- use_module(library(clpfd)). 

nth1(1, [E|_], E). 
nth1(N, [_|Xs], E) :- 
     N #> 1, 
     N #= N1 + 1, 
     nth1(N1, Xs, E). 
+0

Dies hat das gleiche unendliche Rekursionsproblem wie Shuyins Lösung und ist nicht sehr effizient. +1 für Eleganz obwohl. (Noch, ich würde eine Einschränkung 'N #> 1 'hinzufügen, und vielleicht einen Schnitt, für die Effizienz.) –

+1

Ja, Hinzufügen von N #> 1 zum zweiten Satz ist eine gute Idee, ich denke, das entfernt die unendliche Rekursion Sie gemeint, dh für Anfragen wie? - nth1 (3, Es, X)? Das Hinzufügen eines Schnitts zur ersten Klausel würde jedoch gültige Lösungen beispielsweise für die allgemeinste Abfrage - nth1 (N, Ls, E) eliminieren und somit das Prädikat unvollständig machen. – mat

+0

du hast absolut recht. –