Ich habe eine Übung in Python wie folgt:
Ein Polynom wird als Tupel von Koeffizienten angegeben, so dass die Potenzen durch die Indizes bestimmt werden, z. B.: (9,7,5) bedeutet 9 + 7 * x + 5 * x ^ 2
Schreiben Sie eine Funktion, um ihren Wert für ein gegebenes x zu berechnen
Da ich mich in letzter Zeit mit funktionaler Programmierung beschäftige, habe ich geschrieben
def evaluate1(poly, x):
coeff = 0
power = 1
return reduce(lambda accu,pair : accu + pair[coeff] * x**pair[power],
map(lambda x,y:(x,y), poly, range(len(poly))),
0)
was ich für unlesbar halte, schrieb ich
def evaluate2(poly, x):
power = 0
result = 1
return reduce(lambda accu,coeff : (accu[power]+1, accu[result] + coeff * x**accu[power]),
poly,
(0,0)
)[result]
Das ist mindestens genauso unlesbar, also schrieb ich
def evaluate3(poly, x):
return poly[0]+x*evaluate(poly[1:],x) if len(poly)>0 else 0
Das könnte weniger effizient sein (edit: Ich habe mich geirrt!), da es viele Multiplikationen anstelle von Potenzierung verwendet. Im Prinzip interessieren mich Messungen hier nicht (edit: Wie dumm von mir! Messen hätte auf mein Missverständnis hingewiesen!) und immer noch nicht so lesbar (wohl) wie die iterative Lösung:
def evaluate4(poly, x):
result = 0
for i in range(0,len(poly)):
result += poly[i] * x**i
return result
Gibt es eine rein funktionale Lösung, die so lesbar wie der Imperativ ist und deren Effizienz nahe kommt?
Zugegeben, eine Änderung der Repräsentation würde helfen, aber dies wurde durch die Übung gegeben.
Kann auch Haskell oder Lisp sein, nicht nur Python.
for
, dass beispielsweise keine Schleifen verwendet werden) ein schlechtes Ziel in Python. Das vernünftige erneute Binden von Variablen und das Nicht-Mutieren von Objekten bietet Ihnen fast alle Vorteile und macht den Code unendlich lesbarer. Da Zahlenobjekte unveränderlich sind und nur zwei lokale Namen neu binden, erkennt Ihre "imperative" Lösung funktionale Programmiertugenden besser als jeder "streng reine" Python-Code.lambda
Vergleich zu Sprachen mit einer leichteren anonymen Syntaxfunktion notorisch hässlich, wenn Sie mit der Verwendung beginnen . Ein Teil davon trägt wahrscheinlich zum "unreinen" Aussehen bei.Antworten:
Horners Methode ist wahrscheinlich rechnerisch effizienter, wie @delnan hervorhebt, aber ich würde dies in Python für die Exponentiationslösung als ziemlich lesbar bezeichnen:
quelle
sum(coeff * X**power for power, coeff in enumerate(poly))
map
undfilter
. Man kann es sich auch als for-Schleife einer bestimmten Form vorstellen, aber Schleifen dieser Form entsprechen dem oben erwähnten Funktionskombinator.Viele funktionale Sprachen verfügen über Mapi-Implementierungen, mit denen Sie einen Index durch eine Karte weben können. Kombiniere das mit einer Summe und du hast folgendes in F #:
quelle
map
Fall ist, sollte es ziemlich einfach sein, eine eigene zu schreiben , solange Sie verstehen, wie dies funktioniert.Ich verstehe nicht, wie sich Ihr Code auf den von Ihnen definierten Problembereich bezieht, daher gebe ich meine Version dessen, was Ihr Code tut, und ignoriere den Problembereich (basierend auf dem von Ihnen geschriebenen imperativen Code).
Ziemlich lesbares Haskell (dieser Ansatz kann leicht in jede FP-Sprache übersetzt werden, die eine Listendestrukturierung aufweist und rein und lesbar ist):
Manchmal ist der naive einfache Ansatz in haskell so sauberer als der prägnantere Ansatz für Menschen, die weniger an FP gewöhnt sind.
Ein klarer zwingender Ansatz, der immer noch völlig rein ist, ist:
Der Bonus für den zweiten Ansatz ist, dass er in der ST-Monade sehr gut abschneidet.
Obwohl dies sicher ist, wäre die wahrscheinlichste echte Implementierung eines Haskellers die in einer anderen Antwort oben erwähnte Zipwith.
zipWith
ist ein sehr typischer Ansatz und ich glaube, Python kann den Zipping-Ansatz der Kombination von Funktionen und einem Indexer nachahmen, der zugeordnet werden kann.quelle
Wenn Sie nur ein (festes) Tupel haben, warum nicht (in Haskell):
Wenn Sie stattdessen eine Liste von Koeffizienten haben, können Sie Folgendes verwenden:
oder mit einer Reduzierung, wie Sie es hatten:
quelle
tuple
einen Satz von Werten mit fester Größe verstanden, von denen jeder möglicherweise unterschiedliche Typen hat und die nicht hinzugefügt oder daraus entfernt werden können. Ich habe nie wirklich verstanden, warum eine dynamische Sprache mit Listen, die heterogene Eingaben akzeptieren, diese benötigen würde.Es gibt eine allgemeine Reihe von Schritten, mit denen Sie die Lesbarkeit von Funktionsalgorithmen verbessern können:
evaluateTerm
einen langen Lambda-Ausdruck zu lesen . Gerade weil Sie können ein Lambda verwenden nicht unbedingt , dass Sie sollten .enumerate
oderzipWith
.quelle