Frage

Wenn also ein Sprach Verfahren höherer Ordnung liefert dann kann ich Prozedur, die Prozedur gibt. So etwas wie:

(define (Proc a b c)
  (lambda (x) ( #| method body here in terms of a b c and x |# )))

neues Verfahren zu erstellen, würde ich nur, wie etwas tun:

(define ProcA (Proc a1 b1 c1)) ; Would create ProcA that has 1 argument

ähnliche Aufgabe in einer Sprache getan werden könnte, die nicht höhere Ordnung Verfahren unterstützt durch die Definition Proc, die 4 statt 3 Argumente und riefen diese Prozedur ProcA zu definieren nehmen, wie:

(define (Proc a b c x) ( #| method body -- does not return any procedure |# )
(define (ProcA x) (Proc a1 b1 c1 x))

Warum gibt es so viel Flaum über höherer Ordnung Verfahren? Bin ich etwas fehlt?

War es hilfreich?

Lösung

Es ist eine gute Beobachtung, dass eine Funktion, die eine andere Funktion die gleiche wie eine Funktion zurückgibt, die zwei Argumente übernimmt. Dies wird als „Currying“ genannt. Anders ausgedrückt, eine Funktion von A nach B ist ein Beweis für eine logische Folgerung, dass A impliziert B, oder:

A => B.

Wie Sie beachten, wenn A bedeutet, dass B bedeutet, C, dann A und B bedeutet, C, oder:

(A => (B => C)) <==> ((A, B) => C)

Aber eine Funktion höherer Ordnung ist nicht unbedingt eine Funktion, die eine andere Funktion zurückgibt. Eine Funktion höherer Ordnung ist eine Funktion, die eine andere Funktion als Argument . Dies ist ein wichtiger Unterschied, und Hofs sind enorm leistungsfähige Programmierwerkzeuge.

Zum Beispiel, betrachten Sie diese Haskell-Funktion:

map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = f x : (map f xs)

Diese Funktion höherer Ordnung nimmt eine Funktion f und wendet sie in einer Liste für jedes Element. In Sprachen ohne Höfs, würden Sie tun, was diese Funktion tut mit einer Schleife oder etwas Ähnliches, aber in einer Sprache, die Höfs hat, können Sie f für jedes Element in der Liste mit einem einfachen Aufruf wie folgt aufrufen:

map f myList

Sicher, Kontrollstrukturen in Sprachen lassen nähern Sie Funktionen höherer Ordnung, aber eine Sprache, die Funktionen höherer Ordnung hat können Sie Ihre eigenen Steuerkonstrukte erfinden . Scheme sicher qualifiziert.

Andere Tipps

Ich werde nicht versuchen, das Argument hier, aber in rekapitulieren Warum Functional Programming Matters , argumentiert John Hughes, dass Funktionen höherer Ordnung nützlich sind, da sie effektivere Wege zur Verfügung stellen, um „zusammenkleben“ Teile eines Programms, und damit sie es leichter Code wiederverwenden. Die Beispiele sind in einer sehr alten Sprache, die viel länger ist nicht verwendet, aber sie sind immer noch leicht zu folgen und ziemlich überzeugend. Johns Papier zu lesen, ist ein guter Weg, eine detaillierte Antwort auf Ihre Frage zu bekommen: „Warum gibt es so viel Flaum über Prozeduren höherer Ordnung“.

Das ist mehr über mindset als Machbarkeit. Es ermöglicht Ihnen, Funktionen als Bürger erster Klasse zu behandeln, und in Bezug auf die Funktionen vorstellen, die auf Funktionen arbeiten andere Funktionen zu erstellen, etc.

Natürlich könnten Sie diese mit anderen Sprachen zu tun oder simulieren, aber wenn es nicht ein syntaktischer Mechanismus ist, ist es Art als Zusatz oder einen Hack behandelt.

OK, aber im zweiten Beispiel, sind Sie mit einer vorherbestimmten Liste der a1, b1 und c1 dieses Verfahren bei der Kompilierung zu schaffen. Im ersten Beispiel, sind Sie es zur Laufzeit erstellen, wenn Sie ProcA nennen, und Sie können so viele verschiedene, als Sie bitte erstellen, so dass Sie viel mehr interessante Dinge tun können.

Betrachten einer Transformationsfunktion oder ein Sortieralgorithmus durch ein Array. Jetzt wollen Sie es wirklich flexibel machen, wie der Benutzer Ihrer Funktion zu lassen, das Verhalten Ihrer Funktion an, indem sie eine Funktion als Argument übergeben zu lassen.

Sprich: Sie schreiben einen Sortieralgorithmus mit dem folgende Verfahren Prototyp:

sort(Array a, void (*fn)(a::element_type, a::element_type));

Der Benutzer dieser Funktion könnte angeben, indem Sie die entsprechende fn vorbei, wenn sie eine absteigende oder aufsteigende Reihenfolge wollen.

Sie müßten eine innere Klasse zu, dass richtig zu simulieren. Der erste Fall wird Proc über a, b und c geschlossen. Im zweiten Fall kann der Anrufer von Proca nicht kontrollieren, wie a1, b1 und c1 auf die anderen Prozedur übergeben werden, kann er nur x steuern. So, so, wie Sie a1 steuern, b1 und c1 sind durch die Verwendung Variablen auf einem höheren Umfang (Modulebene oder so), die Ihre Funktion nicht rein macht. In diesem Fall können Sie nicht sicherstellen, dass die gleichen Argumente für Anrufe gegeben, Proca das gleiche Ergebnis zurück. Wo, wie mit Proc, können Sie immer sicher sein, dass, wenn Sie es mit den gleichen Argumenten aufrufen, werden die gleichen Ergebnisse passieren.

Ich benutze Funktionen höherer Ordnung in Javascript, zum Beispiel, wenn ich eine Auswahlbox verwenden. Ich kann in der Funktion übergeben, die aufgerufen werden, wenn eine Option ausgewählt ist, als der einzige Unterschied war für mich das, was meinen Code vereinfacht, es Redundanz verringert.

Ich sehe die gleiche Sache in anderen Sprachen, die ich verwenden, die unterstützt Funktionen höherer Ordnung, wie ich dann zu sehen beginnen, wie mein Code aufzuräumen, wo es eine gewisse Redundanz ist, die lokalisiert werden können und Unterschiede können sein erfolgt in einer Funktion.

Sobald C # diese unterstützt, wusste ich, es war jetzt mehr Mainstream. :)

Wenn eine Funktion übernimmt und / oder gibt eine Funktion, wird es eine Funktion höherer Ordnung (HOF). Für unerfahrene Programmierer, die aus C, C ++ oder Java, Funktionen höherer Ordnung klingen wie Magie, aber sie sind sehr einfach. Stellen Sie sich eine einfache Funktion, die das Ergebnis von 2 + 3 zurückgibt:

(define (foo) (+ 2 3)) ;; (foo) => 5

Das ist eine langweilige Funktion, fügt immer 2 bis 3. Was passiert, wenn wir verallgemeinern es, so dass es 2 erhöht nicht nur 3, sondern für alle Benutzer bereitgestellte Nummer?

(define (foo n) (+ 2 n)) ;; (foo 10) => 12

Wenn eine Sprache nicht Höherwertige Funktionen nicht unterstützt, sind Sie zu denken gezwungen, dass Funktionen und Werte (zum Beispiel Zahlen, Boolesche Werte, Listen) sind 2 verschiedene Dinge. Aber funktionale Programmierung (FP) verwischte Unterscheidung zwischen ihnen. Stellen Sie sich vor, dass der einzige Unterschied zwischen einer Funktion und einem Wert wird, dass eine Funktion aufgerufen werden kann, außer, dass Sie auf eine Funktion tun können, was auch immer Sie könnte zu einem 2 oder #t oder '(a b c): Sie können es als ein Argument geben könnte, oder Rückkehr aus eine Funktion oder Speicher in einer variablen oder in einer Liste setzen. Zum Beispiel wollen wir unsere kleine Funktion verallgemeinern weiter, so könnte nicht nur zum 2 n hinzufügen, aber multiplizieren 2 durch n oder gelten andere Funktion, die zwei Zahlen annehmen würde:

(define (foo f n) (f 2 n))
;; (foo + 10) => 12
;; (foo * 10) => 20
;; (foo expt 10) => 1024

Wenn Sie feststellen, dass eine Funktion die gleiche Art und Weise behandelt werden können, eine Zahl oder ein String behandelt wird, anonym Funktionen machen durchaus Sinn ( „Lambda-Ausdrücke“ in FP-Jargon genannt). Anonyme Funktionen sind eigentlich basische und „normal“ als gewöhnliche genannte Funktionen, benannte Funktionen nur anonyme Funktionen in eine Variable gesetzt sind, so wie wir eine Zahl in eine Variable setzen, es zu benutzen mehrmals.

(+ 2 2) ;; is no different from:
(let ((a 2)) (+ a a))
(lambda (x y) (* x y)) ;; is no different from:
(define (foo x y) (* x y)) ;; which is an abbreviation for:
(define foo (lambda (x y) (* x y))).

So Höfs ermöglicht es uns, unsere Funktionen zu verallgemeinern, um sie super-flexibel. Wenn Sie in Ihrer Funktion aussehen, dahinter die Logik sehen, können Sie erkennen, dass, wenn etwas auf Ihre Daten arbeitet, dann etwas anderes könnte wahrscheinlich auch. Wenn Sie zwei Zahlen addieren, könnten Sie wahrscheinlich mehren, oder subtrahieren oder einem zum anderen potenzieren, oder was auch immer. Anstatt eine neue Funktion für jeden Fall jedes Mal zu schreiben, könnten Sie einfach einen zusätzlichen Parameter akzeptieren, die eine Funktion sein muss.

In FP verwenden wir Höfs die ganze Zeit, zum Beispiel, wenn Listen zu manipulieren. 3 Funktionen sind Brot und Butter von FP: map , filter und foldl . map übernimmt eine Funktion mit 1 Argument gilt diese Funktion für jedes Element einer Liste und gibt eine neue Liste mit geänderten Elemente. filter akzeptiert ein Prädikat (Funktion, die einen Booleschen Wert zurück) mit 1 Argumente gilt das Prädikat auf jedes Element einer Liste und gibt eine neue Liste mit Elementen, die das Prädikat entfernt nicht erfüllen.

(map (lambda (n) (+ n 1)) '(1 2 3 4 5) ;; '(2 3 4 5 6)
(define (foo n) (+ n 1))
(map foo '(1 2 3 4 5)) ;; '(2 3 4 5 6)
(filter (lambda (n) (> n 3)) '(1 2 3 4 5)) ;; '(4 5)
(define (bar n) (> n 3))
(filter bar '(1 2 3 4 5)) ;; '(4 5)

Stellen Sie sich vor, Sie haben eine Liste von 1-arity Funktionen wieder, können Sie tun, was Sie mit einer Funktion möchten, und speichern sie in einer Datenstruktur zu-und Sie wollen alle von ihnen auf die gleiche Nummer beantragen, und erhält eine Liste der Ergebnisse.

(let ((xs (list (lambda (x) (+ x 1))
                (lambda (x) (* x 2))
                (lambda (x) (- x)))))
  (map (lambda (f) (f 10)) xs)) ;; => (11 20 -10)

Fazit: , wenn eine Programmiersprache Konzepte richtig funktionale Programmierung unterstützt, Funktionen höherer Ordnung erlauben flexibility und Allgemeinheit, die Ihren Code sowohl leistungsfähiger macht und prägnant (Sie können die gleiche Funktion für verschiedene Anwendungsfälle verwenden) (keine Notwendigkeit, 10 Versionen einer Funktion zu schreiben). Einige Funktionen höherer Ordnung sind stark in der funktionalen Programmierung verwendet, so dass Sie von Low-Level loszuwerden und ausführliche for-Schleifen und schreiben Einzeiler, die alles tun, statt.

Hinweis: foldl, die die gleichen wie „links fold“ oder „links reduzieren“, ist noch leistungsfähiger. Wenn Sie wirklich interessiert sind und Zeit haben, können Sie die erste Hälfte des meine Antwort verwenden reduzieren. Es ist zwar nicht für Schema / Racket geschrieben, sondern für Common Lisp / Emacs Lisp, können Sie immer noch die Idee hinter Falte verstehen / reduzieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top