2016-04-07 3 views
5

Ich versuche herauszufinden, wie ein Prädikat in Prolog erstellt wird, das die Quadrate nur der geraden Zahlen in einer gegebenen Liste summiert.Erstellen eines Prädikats in Prolog, das die Quadrate nur der geraden Zahlen in einer Liste summiert

Erwarteter Ausgang:

?- sumsq_even([1,3,5,2,-4,6,8,-7], Sum). 

Sum = 120 ; 

false. 

Was ich weiß, wie zu tun ist, um alle ungeraden Zahlen aus einer Liste zu entfernen:

sumsq_even([], []). 
sumsq_even([Head | Tail], Sum) :- 
    not(0 is Head mod 2), 
    !, 
    sumsq_even(Tail, Sum). 
sumsq_even([Head | Tail], [Head | Sum]) :- 
    sumsq_even(Tail, Sum). 

Was mich gibt:

Sum = [2, -4, 6, 8] 

Und Ich weiß auch, wie man alle Quadrate der Zahlen in einer Liste summiert:

sumsq_even([], 0) 
sumsq_even([Head | Tail], Sum) :- 
    sumsq_even(Tail, Tail_Sum), 
    Sum is Head * Head + Tail_Sum. 

Aber ich kann anscheinend nicht herausfinden, wie man diese zwei zusammen verbindet. Ich denke, dass ich in die falsche Richtung gegangen bin, aber ich bin mir nicht sicher, wie ich richtige Beziehungen definieren soll, damit es Sinn ergibt.

Danke!

+0

Idealerweise sind Ihre Prolog-Programme reine * Relationen *. Dies bedeutet, dass sie in allen Richtungen verwendbar sein sollten, beispielsweise auch im allgemeinsten Fall. Zum Beispiel möchten wir auch Antworten für "? - sumbsq_even (Ls, Sum)." Lesen Sie die Antworten von @repeat und @tas für diese Allgemeingültigkeit. – mat

Antwort

2

Teilen Sie Ihr Problem in kleinere Teile auf. Wie Sie bereits gesagt, haben Sie zwei verschiedene Funktionalitäten, die kombiniert werden sollen:

  • entfernen ungerade Zahlen aus einer Liste (even)
  • Summe aller Quadrate der Zahlen in einer Liste (sumsq)

also in erster Linie verwenden unterschiedliche Prädikat Namen für verschiedene Funktionalitäten:

even([], []). 
even([Head | Tail], Sum) :- 
    not(0 is Head mod 2), 
    !, 
    even(Tail, Sum). 
even([Head | Tail], [Head | Sum]) :- 
    even(Tail, Sum). 

sumsq([], 0). 
sumsq([Head | Tail], Sum) :- 
    sumsq(Tail, Tail_Sum), 
    Sum is Head * Head + Tail_Sum. 

in einem dritten Prädikat c Sie ein nun die beiden nachfolgenden kleineren Schritten kombinieren:

sumsq_even(List, Sum) :- 
    even(List, Even_List), 
    sumsq(Even_List, Sum). 

In dieser Regel wird zunächst die (Eingang) Liste reduziert wird, um auch Elemente (Even_List) und nach, dass die Summe der Quadrate berechnet.

Dies ist das Ergebnis für Ihr Beispiel:

sumsq_even([1,3,5,2,-4,6,8,-7], Sum). 
S = 120. 
2

Sie können beide Aufgaben tatsächlich tun (Filtern der geraden Anzahl und ihnen Summieren) auf einmal:

:- use_module(library(clpfd)). 

nums_evensumsq([],0). 
nums_evensumsq([X|Xs],S0) :- 
    X mod 2 #= 0, 
    nums_evensumsq(Xs,S1), 
    S0 #= S1 + X * X. 
nums_evensumsq([X|Xs],S) :- 
    X mod 2 #= 1, 
    nums_evensumsq(Xs,S). 

Abfrage das Prädikat das gibt gewünschtes Ergebnis:

?- nums_evensumsq([1,3,5,2,-4,6,8,-7],S). 
S = 120 ? ; 
no 

können Sie schreiben es noch kürzer mit IF_/3 alsdefiniert:

nums_evensumsq([],0). 
nums_evensumsq([X|Xs],S0) :- 
    nums_evensumsq(Xs,S1), 
    Y #= X mod 2, 
    if_(Y = 0, S0 #= S1 + X * X, S0 #= S1). 

anzumerken, dass der Vergleich im ersten Argumente von IF_/3 = mit/3 definiert here erfolgt.

+1

Wow! Es funktioniert in alle Richtungen! – mat

+1

Ein Detail ist eigentlich ein bisschen aus ... Was ist mit der Zusammenfassung ** Quadrate **? – repeat

+1

@repeat: Wie peinlich. Es war direkt vor meinen Augen. Danke für den Hinweis, ich habe meinen Code korrigiert. – tas

0

Sobald Sie die Grundlagen beherrschen, könnten Sie interessiert sein, über Butintins zu lernen.Bibliothek aggregate, bietet eine einfache Möglichkeit, Listen zu handhaben, indem Mitglied/2 als Listenelement 'Accessor':

sumsq_even(Ints, Sum) :- 
    aggregate(sum(C), I^(member(I, Ints), (I mod 2 =:= 0 -> C is I*I ; C = 0)), Sum). 
+1

Es gibt keine Notwendigkeit, wenn-dann-sonst hier zu verwenden. 'C = 0' trägt nichts zur Summe bei! – repeat