Eingabe / Ausgabe in 'mathematischen' Programmiersprachen [geschlossen]

Mehr als einmal habe ich das beobachtet: Eine Person beschreibt eine funktionale Programmiersprache (im Gegensatz zu einer Programmiersprache, die stark von eingestreuten Zuständen Gebrauch macht), diese Person wird sagen, dass sie sehr mathematisch ist, also sollten wir die Sprache der Mathematik verwenden; beginnt dann, um es zu demonstrieren, "Nehmen wir an, wir haben eine Funktion f, die die Eingabe x nimmt und die Ausgabe y zurückgibt ..." oder so ähnlich.

Das nervt mich, weil ich noch nie gehört habe, dass ein Mathematiker eine Funktion so beschrieben hat, dass sie Eingaben nimmt und Ausgaben gibt. Stattdessen, glaube ich, wird eine Funktion als Karte betrachtet, und man könnte sagen, dass die Domäne, die Karte und die Co-Domäne alle gleichzeitig existieren.

In der Welt der Computerverarbeitung ist eine bestimmte Zeitdauer typischerweise mit einer Operation verbunden, muss es aber nicht sein: Es könnte sein, dass die Sprachrepräsentation die Operation nicht wirklich direkt darstellt (die Funktion könnte sogar vollständig von der entfernt werden Code-Compiler oder -Interpreter), oder vielleicht benötigt die Funktion tatsächlich eine andere Eingabe als gedacht, ist auf viele Prozessoren verteilt usw. Kurz gesagt, die Maschinenoperationen werden nicht unbedingt auf einfache Weise für die menschliche Interpretation durch die Programmiersprache dargestellt .

Außerdem kann die Zeit für die Operation vernachlässigbar sein, sie kann parallel zu einer anderen Operation ausgeführt werden, oder die Schritte eines Programms können in einer anderen Reihenfolge ausgeführt werden. Es könnte sogar einige andere spätere Operationen erfordern, die für den Beobachter nicht offensichtlich sind, und so einen Einfluss auf andere Zeitpunkte haben.

Ich denke jedoch, dass ein grundlegenderer Konflikt möglich ist. Wie von Schopenhauer in „Die vierfache Wurzel“ ausgedrückt, gibt es ein Problem, das Konzept der „Ursache“ im physikalischen Sinne auf die Metapher der logischen „Ursache“ anzuwenden.

Die Computerverarbeitung scheint sich genau in der Lücke zwischen „Inferenz als physikalisches Modell“ und „Inferenz als logisches Modell“ zu befinden. Ist das ein grundlegendes Problem, wie ich es ausgedrückt habe? Ist es möglich, dass diese gemischten Metaphern mit fortschreitender Entwicklung der Datenverarbeitung problematischer werden?

Während ich Absätze und Formatierungen sehe (was ein gutes Zeichen ist), sehe ich nicht ganz, wo die Philosophiefrage ist. Ich sehe jedoch viele Aussagen über Computer. Könntest du die Frage, die du hier stellst, irgendwie hervorheben?
Willkommen in der Philosophie! Diese Art liest sich eher wie eine Antwort als eine Frage – besteht die Möglichkeit, dass Sie versuchen könnten, etwas expliziter zu spezifizieren, was genau das Problem ist, auf das Sie in Ihrem Studium der Philosophie stoßen? Wie sieht eine Antwort auf diese Frage in Ihrem Kopf aus? was genau soll dir hier jemand (in wenigen absätzen) erklären?
Hallo Danke! Vielleicht war meine Frage eher eine Antwort als eine Frage und vielleicht ein bisschen weit gefasst. Ich hatte wirklich gehofft, mein Studium zu erweitern, indem ich als Antwort eine Referenz in Philosophie oder Geschichte bekomme. Die Antwort von @CortAmmon war gut, aber ich dachte, "alles ist möglich" und "Metaphern ändern" kommen nicht ganz auf den Punkt, obwohl sie möglicherweise erweitert wurden. Der Abschnitt „In Kürze“ von Keelans Antwort war zwar etwas meinungsbasiert, aber ein ziemlich guter Überblick. Die Antwort von quen_tin war gerichtet, hatte aber keine unterstützende Referenz. FredBarker hatte eine Referenz, kam aber nicht ganz zum Thema.

Antworten (3)

Ich glaube nicht, dass wir wirklich etwas anderes tun, als unterschiedliche Wörter für dieselbe Sache zu verwenden. Wenn Sie sich zum Beispiel die Haskell- modFunktion für Modulo ansehen :

mod :: a -> a -> a

Mathematisch gesehen ist die Modulo-Funktion so etwas wie   Z × Z → N   (wobei Z die Menge der ganzen Zahlen ist; N die Menge der natürlichen Zahlen, nicht negative ganze Zahlen).

Sie können das gleiche in Haskell sehen, außer dass sie nicht zwischen Z und N unterscheiden, was mathematisch korrekt ist, und dass sie nur Pfeile anstelle von × und einem Pfeil verwenden.

In der Mathematik nennen wir die linke Seite des Pfeils den Bereich und die rechte Seite den Kobereich; Bei der funktionalen Programmierung nennen wir links die Eingänge und rechts die Ausgänge.

Die Verwendung der Wörter „Eingabe“ und „Ausgabe“ im Zusammenhang mit einer funktionalen Programmiersprache ist schrecklich , da Eingabe- und Ausgabeänderung und funktionale Sprachen auf der Idee basieren, dass sich die Dinge nicht ändern. Wenn Sie tatsächliche Ein- und Ausgaben verwenden (Dinge, die sich ändern), verwenden Sie die Sprache auf eine Weise, die nicht mehr streng funktional ist, mit der Verwendung von monads . Wenn jedoch jemand das Konzept einer funktionalen Sprache versteht, kann die Verwendung von „Eingabe“ und „Ausgabe“ meiner Meinung nach nicht mehr schaden als etwas Verwirrung stiften.

Sie sprechen auch über den Unterschied, dass das Rechnen Zeit braucht. Funktionale Sprachen sind manchmal faul , was bedeutet, dass man Dinge nur dann berechnet, wenn es nötig ist. Zum Beispiel können wir die ganze (unendliche) Menge natürlicher Zahlen in eine Liste aufnehmen, solange Sie ihr nicht sagen, dass sie alle Mitglieder berechnen soll (indem Sie nach der Summe fragen oder so etwas). Dieses Konzept der Faulheit ist tatsächlich sehr ähnlich zu dem, was wir in der Mathematik tun. Wenn wir etwas beweisen, berechnen wir selten wirklich etwas.

Der Punkt der physikalischen Inferenz im Vergleich zur logischen Inferenz ist ein guter Punkt, besonders da die Herstellung von Hardware für funktionale Sprachen schwierig ist . An der Universität von York wird geforscht, wo sie den Reduceron entwickeln , aber soweit ich weiß, ist dies noch nicht auf einem Niveau, auf dem wir sehen können, dass die Maschine voll funktionsfähig ist .

Vielleicht, aber ich bin mir nicht sicher, ist dies (physische Ebene vs. logische Ebene) tatsächlich der Grund dafür, dass es so schwierig ist, Hardware herzustellen: dass wir versuchen, etwas zu bauen, das in eine völlig andere Welt gehört. War Schopenhauer vielleicht der erste Informatiker? :)

Ich bin mir der Einschränkungen funktionaler Programmiersprachen nicht ganz bewusst, aber es ist theoretisch möglich, sie anzuweisen, etwas zu berechnen, wofür sie etwas Unendliches benötigen (sei es Zeit oder Speicher), während Mathematik dies ohne große Probleme tun kann.

Zusamenfassend:

  • Ich glaube nicht, dass funktionale Sprachen Funktionen viel anders behandeln als Mathematik, obwohl Programmierer möglicherweise verwirrende Begriffe verwenden.
  • Der Unterschied in der Betriebszeit kann durch Lazy Execution stark verringert werden .
  • Physikalische Kausalität, die versucht, logische Kausalität zu imitieren, kann sicherlich Probleme verursachen, aber so weit sind wir noch nicht.
Ich glaube nicht, dass Quantencomputer den Zeitpfeil oder so etwas umkehren würden, aber ich frage mich, ob es das Verständnis der Verarbeitungszeit mit umkehrbaren Operationen und dergleichen ändern könnte. Übrigens: Ich habe erst vor kurzem angefangen, Clojure für Webscripting zu verwenden, bin aber irgendwie von Haskell abgeprallt. Ich kann nicht umhin, mich zu fragen, ob ich etwas davon vermissen werde.
@dwn Ein wichtiger Unterschied besteht darin, dass Clojure unrein ist, „da es Ihr Programm nicht dazu zwingt, referenziell transparent zu sein, und nicht nach „beweisbaren“ Programmen strebt. Die Philosophie hinter Clojure ist, dass die meisten Teile der meisten Programme funktionsfähig sein sollten“ (von clojure.org/functional_programming ) – wenn die Sprache nicht voll funktionsfähig ist, können andere Dinge zutreffen. Soweit ich weiß, kommt Haskell der vollen Funktionalität am nächsten. Das macht es jedoch auch etwas schwierig, es zu verwenden, wenn Sie nicht etwas rein mathematisches tun.
@Keelan - Nun, Idris? Koq? Haskell ist nicht wirklich die funktionalste , nur die funktionalste der wohl in der realen Welt verwendbaren Sprachen (insofern es Bibliotheken hat, mit Tastatureingaben umgehen kann usw.).
Es ist nicht so, dass funktionale Sprachen, selbst reine funktionale Sprachen, im Allgemeinen faul sind. Haskell ist darin ungewöhnlich. (Sie ist auch unter den rein funktionalen Sprachen ungewöhnlich prominent.)
@RexKerr danke, mein Wissen reicht nicht so weit.
@ChristianConkle danke auch, das wusste ich nicht.

Faule Antwort: Ja, alles ist möglich

Okay, jetzt für die längere Antwort

Ich denke, der Wortlautunterschied zwischen "Eingabe / Ausgabe" und "Zuordnung" wird aufgrund von Nebenwirkungen verwendet. Mathematische Abbildungen haben keine Seiteneffekte, sie sind einfach Abbildungen. Der Unterschied zwischen einem Wert 1 und einer komplizierten Gleichung, die an einem Punkt ausgewertet wird, der auf 1 abgebildet wird, ist unwichtig, es sei denn, Sie möchten die Gleichung explizit bearbeiten.

Funktionale Programmiersprachen versuchen Nebeneffekte zu vermeiden, um eine ähnliche mathematische Reinheit zu erreichen. Es gibt jedoch Nebenwirkungen, die nicht vermieden werden können, wie z. B. der Verbrauch von Rechenressourcen. Dies zwingt die Menschen dazu, etwas weniger mathematisch zu denken. Zum einen hat jede funktionale Programmiersprache mindestens ein prozedurales Konzept, „evaluate“, das den Prozess anstößt. Dieser kleine Kernel zwingt Programmierer, etwas anders zu denken.

Die funktionalen Programmierer haben ein gültiges Argument: Wenn ich f(1, 2) auswerten muss, ändert sich die Antwort nicht, wenn ich f(1,2) und f(3, 4) auswerte. Eine funktionale Sprache könnte man sich als alle Werte gleichzeitig vorstellen, im Vergleich zu prozeduralen Sprachen, die Nebenwirkungen haben, die uns daran hindern, beliebigen Code auszuführen.

Ob Metaphern problematischer werden, hängt davon ab, was Sie als problematisch erachten. Bedenken Sie, dass alle Metaphern zu allen Zeiten problematisch waren, denn so funktionieren Metaphern. Es gibt kein Studiengebiet auf der ganzen Welt, das nicht über ein Ökosystem von Metaphern verfügt, die entstehen, wenn sie hilfreich sind, und schwinden, wenn sie weniger nützlich sind. Ich gehe davon aus, dass sich dieses Muster in der Computertechnik fortsetzen wird.

Es gibt bereits großartige Beispiele für Orte, an denen Metaphern zusammengebrochen sind. Denken Sie in der Welt der prozeduralen Programmierung an Multithreading. Die längste Zeit konnten wir die von Neuman-Maschine als Metapher für unseren eigentlichen Computer verwenden. Bei modernen atomaren Operationen sind wir jedoch gezwungen, das Vorhandensein von Speichercaches und anderen Dingen zuzugeben, die in der Metapher nicht vorkommen. C++ hat gerade eine neue Spezifikation veröffentlicht, die atomare Operationen enthält. 90 % der Behandlung von Atomen in der Spezifikation beziehen sich jetzt auf Dinge, die nicht mit der von Neuman-Maschine erklärt werden können. Die Lösung bestand darin, dass C++ eine neue Metapher erfand: das C++11-Speichermodell, das dem näher kommt, was moderne Hardware tut. Wenn dieses Modell versagt, erfinden wir ein neues.

In der Mathematik wird oft gesagt, dass eine Funktion Eingaben entgegennimmt und Ausgaben liefert. Eine Funktion ist ein restriktiveres Konzept als eine allgemeine Beziehung zwischen zwei Domänen: Sie ordnet jedem Wert der Eingabedomäne nur einen Wert in der Ausgabedomäne zu (es handelt sich um eine Viele-zu-Eins-Beziehung). Dies ist auch ein eindeutiges Merkmal von Funktionen in einer funktionalen Programmiersprache. Eine mathematische Funktion ist streng genommen keine Programmierfunktion, aber aufgrund dieser Ähnlichkeiten ist es eine nützliche Abstraktion, letztere anzusprechen (im Gegensatz zu imperativen Sprachen, wo einige Funktionen zu unterschiedlichen Zeiten unterschiedliche Werte zurückgeben können, z. B. wenn sie Zustandsvariablen verwenden oder externe Eingänge wie Uhr). In jedem Fall gibt es starke Beziehungen zwischen Mathematik und Algorithmik. Beide haben die gleichen logisch-mathematischen Grundlagen.

Der Programmierer kann eine direkte Übereinstimmung zwischen dem Code und dem kompilierten Programm erwarten. Jede implementierte Operation wird als solche ausgeführt. Vielleicht werden sie optimiert, aber das Ergebnis wird vom Compiler garantiert gleich sein. Andernfalls wären Programme nicht zuverlässig. Mit anderen Worten, ein Programmierer kann zuverlässig argumentieren, „als ob“ der Computer den Code tatsächlich zur Ausführungszeit lesen und mathematische Funktionen anwenden würde, wie es ein Mathematiker tun würde.

Optimierungen zur Kompilierzeit führen zu einer geringeren Zuverlässigkeit als bei den Dauererwartungen (nur das Ergebnis ist garantiert), aber in den meisten Fällen führt das Erzielen des gleichen Ergebnisses dazu, dass die gleichen Operationen ausgeführt werden, und eine Schätzung der Dauer auf der Grundlage des Codes ergibt ein ungefähr gutes Ergebnis. Ich denke, die allgemeine Struktur des Programms spiegelt sich im Allgemeinen im kompilierten Programm wider.

In imperativen Programmiersprachen gibt es Techniken, um zur Laufzeit genauere Dauermessungen zu erhalten, die für die Profilerstellung (Verbesserung der Effizienz des Programms) verwendet werden. Ich weiß nicht, ob sie für funktionale Sprachen existieren.