Haskell



  • CStoll schrieb:

    PS: Und kein System der Welt kann dir Garantien bieten, die mathematisch nicht realisierbar sind.

    Eben. Warum reitest du dann darauf herum?

    !rr!rr_. schrieb:

    Ich kann mich jedenfalls nicht erinnern, wann ich zuletzt einen Typfehler bei der Programmierung mit einer dynamisch typisierten Programmiersprache hatte - in den letzten 4 Jahren mit Sicherheit kein einziges Mal.

    Und selbst wenn, dann kann man diese Gefahr (und viele andere mögliche Fehlerquellen) minimieren durch sprechende Bezeichner und vor allem durch feinkörnige Unit-Tests, die synchron mit dem Sourcecode aufgebaut werden.

    Ich weiß nicht, mit welchen dynamisch typisierten Sprachen du so arbeitest; bei mir waren es zuletzt PHP und R, und obgleich ich die Vorteile durchaus sehe - in R hatte ich meinen Spaß damit, die gängigen arithmetischen Operatoren derart zu überschreiben, daß man sie zwecks point-free-Formulierung auch auf Funktionen anwenden kann -, muß ich eigentlich jedes Mal in der Dokumentation nachschauen, welche Datentypen die Funktion nun wirklich behandeln kann, auch wenn mir völlig klar war, was die Funktion tut. In einer statisch typisierten Sprache reicht es, den Parameter-Tooltip der IDE anzustarren.

    Gerade in R kann man mit der unscharfen Trennung zwischen Skalaren und Vektoren viel Mist bauen. Die Sprache erlaubt etwa a * b für beliebige Kombinationen von Vektoren und Skalaren. Haben a und b die gleiche Anzahl Einträge, wird der Operator elementweise angewandt; ist einer davon skalar, so ist es eine skalare Multiplikation. Das ist sehr praktisch, weil ich dann den RMS eines Vektors x mit sqrt(sum(x^2)/length(x)) ausrechnen kann. Ist aber length(a) != length(b) && length(a) != 1 && length(b) != 1 , so gibt es einen Laufzeitfehler, weil R nicht weiß, was es tun soll. Das ist besonders lustig in Verbindung mit den Plot-Funktionen; wenn ich plot(sin) mache, übergibt plot() nicht etwa Skalare, sondern einen Vektor an sin() und erwartet, daß sin() sich selbst elementweise darauf anwendet. Bei sin() klappt das auch, aber bei etwas filigraneren selbstgeschriebenen Funktionen eben oft nicht.

    Dergleichen Wildwuchs kenne ich aus allen dynamisch typisierten Sprachen, die mir begegnet sind. Besonders die Unsitte, daß man, anstelle eine Eigenschaft zu spezifizieren, auch einfach ein Objekt übergeben kann, das diese Eigenschaft hat - das macht den Code unleserlich, führt zu Verwirrung, weil es meist nur in bestimmten Situationen geht, und verursacht oft abenteuerliche Laufzeitfehlermeldungen.

    ertes schrieb:

    Haskell ist besser als C++ für Serverprogramme und Webanwendungen. (Darauf ist bisher keiner richtig eingegangen. Offenbar habe ich da wohl eine echte Schwachstelle von C++ erwischt.)

    Ungefähr niemand macht Webentwicklung in C++; warum sollte man auch. Praktisch jeder benutzt ASP.NET oder PHP, Ausnahmen bestätigen die Regel.

    ipsec schrieb:

    Wo du gerade nochmal Agda erwähnst. Du sagst (sinngemäß) Agda ist nicht turingvollständig, weil Endlosschleifen nicht möglich sind, trotzdem sind endlose Programme durch Corekursionen möglich. Für mich ist das ein Widerspruch. Wenn es nicht turingvollständig ist, kann man damit nicht alle Programme schreiben (wie praktisch relevant diese Beschränkung auch immer sein möge). Wenn man solche Programme jetzt doch schreiben kann, ist es doch turingvollständig.

    Ich weiß nicht, was ertes da sagen wollte, aber ein Programm muß nicht turingvollständig sein, nur weil es nicht terminiert.



  • ertes schrieb:

    CStoll schrieb:

    Dann erklär's mir doch mal an einem praktischen Beispiel - […]

    Eine Standardanwendung für GADTs findest du an jeder Ecke im Netz: Eine EDSL für eine kleine Arithmetik-Sprache. Such selber. Ich habe keine Lust mehr.

    bei den arithmetischen Funktionen hast du schließlich schon wieder einen Rückzieher gemacht.

    Nö, hab ich nicht.

    Wo ist dann die Erkläung, wie man Subtraktion und Wurzel typsicher miteinander kombinieren kann. Du hast zwar behauptet, daß das ohne Laufzeitpüfungen geht, aber den Beweis hast du unterschlagen.

    Du postest Fragmente und wenn dich jemand um Details oder Ergänzungen bittet, tust du es mit einem "kann man machen" ab. Und mit deinen Ergüssen hast du bei mir (leider) das genaue Gegenteil erreicht wie bei currywurst. Ich hoffe, bei unserer nächsten Begegnung geht es um etwas, wo du eher gesprächsbereit bist.

    Denkst du eigentlich, ich habe ewig Zeit? Wenn du wirklich Interesse an Haskell hast, dann hörst du auf mich, wenn ich dir fünfhundert mal sage:

    HALLO, KANNST DU LESEN ODER WAS? HASKELL IST DAFÜR NICHT GEEIGNET!

    Du bemerkst anscheinend gar nicht, wie du dir selber widerspichst. Auf der einen Seite sagst du, daß Haskell typische C++ Fehler zur Compilezeit abfangen kann, auf der anderen Seite kommt dann

    HASKELL IST DAFÜR NICHT GEEIGNET!

    Haskell ist typensicher und Programme, die kompilieren, funktionieren meistens auch. Viele Bugs, die in C++ erst zur Laufzeit auftreten würden, fängt in Haskell bereits der Compiler ab. (Eure Interpretation: Ich würde meine Programme nie testen. Ich würde meine Programme so schreiben, dass jede noch so kleine Kleinigkeit statisch garantiert wird.)

    Das liegt aber nur daran, daß Haskell viele Aspekte hinter den Kulissen abwickelt, die der C++ Entwickler direkte beeinflussen kann.
    Außerdem kannst du die falsche Verwendung von Datenypen in C++ genauso unterbinden wie in Haskell (ist nur ein wenig aufwendiger, aber machbar). Die meisten Laufzeitfehler, die mir in letzter Zeit untergekommen sind, basierten auf Rechen- oder Denkfehlern und Daten, die erst zur Laufzeit bekannt sind. Sowas kannst du nicht diagnostizieren indem du es in ein Typ-Korsett presst.

    Haskell ist besser als C++ für Serverprogramme und Webanwendungen. (Darauf ist bisher keiner richtig eingegangen. Offenbar habe ich da wohl eine echte Schwachstelle von C++ erwischt.)

    Web-Anwendungen sind ja auch nicht das Spezialgebiet von C++, dafü gibt es genug andere Sprachen, mit denen du dich vergleichen könntest.

    Haskell muss sich performancemäßig schon lange nicht mehr vor C++ verstecken. (Als Gegenargument bekam ich lediglich einen Shootout-Link, in dem eine schlechte Haskell-Implementierung gegen eine gute C++-Implementierung antritt.)

    Ich hab' den Shootout jetzt nicht im Detail analysiert, aber woher willst du wissen, wie gut die einzelnen Kandidaten tatsächlich optimiert worden sind?

    Von solchen Garantien war auch keine Rede. Aber bedenke, dass einige Garantien nur deshalb nicht möglich sind, weil du in Turing-Maschinen denkst. Ich habe dich diesbezüglich (auch schon wieder mehrfach) auf Agda hingewiesen, eine Sprache, die genau aus diesem Grund nicht turingvollständig ist.

    Klar, wenn man die Möglichkeiten einer Sprache einschränkt, kann man innerhalb dieser Möglichkeiten irgendwann alles beweisen. Das Problem ist, daß du mit einer solchen Sprache schneller an die Grenzen dessen kommst, was du darstellen kannst.
    (Oder habe ich die Entdeckung von etwas verpasst, was echt mächtiger ist als eine Turing-Maschine?)

    !rr!rr_. schrieb:

    man fragt sich, ob Typsicherheit überhaupt diesen unglaublichen Aufwand wert ist.

    Welchen Aufwand denn? Vergiss mal, was CStoll schreibt. Der redet nicht von Typsicherheit, sondern von mathematischen Beweisen. Das hat nichts mit praktischer Typensicherheit zu tun, und ist in Haskell prinzipiell auch nicht gut lösbar. Dafür braucht man einen Beweisassistenten wie Agda oder Coq.

    Du wolltest doch Fehlerfreiheit durch Typsicherheit ausdrücken (oder war das einer der anderen Haskell-Anhänger - jedenfalls kam von einem von euch die Aussage "wenn es sich compilieren lässt, ist es fehlerfrei"?).



  • ertes schrieb:

    Haskell ist typensicher und Programme, die kompilieren, funktionieren meistens auch. Viele Bugs, die in C++ erst zur Laufzeit auftreten würden, fängt in Haskell bereits der Compiler ab. (Eure Interpretation: Ich würde meine Programme nie testen. Ich würde meine Programme so schreiben, dass jede noch so kleine Kleinigkeit statisch garantiert wird.)

    Das rührt aus einem Mißverständnis her.
    Jeder, der "Effektiv C++ programmieren" gelesen und verstanden hat, macht auch in C++ viele Bugs, die in vielen anderen Sprachen erst zur Laufzeit auftreten würden, zu Compilerfehlern. Wir versuchten zu ergründen, was Haskell da an Mehrwert hat. Und Du bliebst für uns enorm schwammig widersprüchlich leer, weil Du einerseits Codebeispiele gezeigt hast, die dann doch zu extrem waren und Du sie selber nicht verwendest, und andererseits Codebeispiele zeigtest, die verwendbar sind und auch in modernem C++ eine Selbstverständlichkeit sind. Es war kein Mehrwert ersichtlich, obwohl Du dauernd den Mehrwert betont hast. Verwirrend. Also fragt man nach. Und es kommt nur weiter *******.
    Wir gingen dummerweise davon aus, daß Du C++ total gut kannst. Weil Du es mehrfach behauptet hast. Ab jetzt spreche ich es auch Dir ab. Es gibt viele mehrjährige C++-Programmierer, die nicht gut sind. Es würde einfach gut erklären, warum Du Dich in Haskell so verknallt hast. Fröhliche Ostern!



  • CStoll schrieb:

    Die meisten Laufzeitfehler, die mir in letzter Zeit untergekommen sind, basierten auf Rechen- oder Denkfehlern und Daten, die erst zur Laufzeit bekannt sind. Sowas kannst du nicht diagnostizieren indem du es in ein Typ-Korsett presst.

    Es kann sich lohnen, "typische" Fehler durchs Typsystem zu verbieten. Ich stelle mir als Beispiel vor, daß man so erzwingt, daß socket::bind aufgerufen wird. Erspart einem auch den Blick ins Handbuch.
    Das Korsett kann ich allerdings erst basteln, wenn ich das richtige Vorgehen herausgefunden habe.
    Aber kaum der Rede wert. Die Arbeitszeitfreßfehler tauchen dort gar nicht auf.



  • ipsec schrieb:

    Wo du gerade nochmal Agda erwähnst. Du sagst (sinngemäß) Agda ist nicht turingvollständig, weil Endlosschleifen nicht möglich sind, trotzdem sind endlose Programme durch Corekursionen möglich. Für mich ist das ein Widerspruch. Wenn es nicht turingvollständig ist, kann man damit nicht alle Programme schreiben (wie praktisch relevant diese Beschränkung auch immer sein möge). Wenn man solche Programme jetzt doch schreiben kann, ist es doch turingvollständig.

    Das bedeutet nur, dass man dennoch Programme schreiben kann, die unendlich lange laufen. Die Sprache wird deshalb aber nicht turingvollständig. Das Halteproblem etwa existiert in Agda nicht. Du kannst einen Algorithmus schreiben, der sagen kann, wann ein Agda-Programm terminiert. Zwei mögliche Ausgaben des Programms sind etwa, dass das Programm immer terminiert, oder dass es terminiert, sobald der Benutzer die "q"-Taste gedrückt hat. So ein Programm kannst du für eine turingvollständige Sprache nicht schreiben.

    audacia schrieb:

    ertes schrieb:

    Haskell ist besser als C++ für Serverprogramme und Webanwendungen. (Darauf ist bisher keiner richtig eingegangen. Offenbar habe ich da wohl eine echte Schwachstelle von C++ erwischt.)

    Ungefähr niemand macht Webentwicklung in C++; warum sollte man auch. Praktisch jeder benutzt ASP.NET oder PHP, Ausnahmen bestätigen die Regel.

    Aber Server-Programmierung wird doch in C++ gemacht, oder irre ich mich? Und Webentwicklung macht niemand in C++, weil es so ungeheuer schwierig ist. Da fängt es ja schon damit an, dass es kaum brauchbare Bibliotheken dafür gibt, ganz zu schweigen von einem richtigen Framework.

    CStoll schrieb:

    bei den arithmetischen Funktionen hast du schließlich schon wieder einen Rückzieher gemacht.

    Nö, hab ich nicht.

    Wo ist dann die Erkläung, wie man Subtraktion und Wurzel typsicher miteinander kombinieren kann. Du hast zwar behauptet, daß das ohne Laufzeitpüfungen geht, aber den Beweis hast du unterschlagen.

    Ja, weil ich zufällig auch noch ein Leben habe. Außerdem habe ich die Erklärung gegeben, nur eben ohne Beispielcode. Ich habe einfach Besseres zu tun als eine Stunde lang für dich ein Code-Beispiel auszuarbeiten. Ja, es dauert wirklich so lange, weil Haskell (und jetzt sage ich es schon wieder) nicht dafür geeignet ist. Letzter Beitrag zu dem Thema.

    Du bemerkst anscheinend gar nicht, wie du dir selber widerspichst. Auf der einen Seite sagst du, daß Haskell typische C++ Fehler zur Compilezeit abfangen kann, auf der anderen Seite kommt dann

    HASKELL IST DAFÜR NICHT GEEIGNET!

    Ein typischer C++-Fehler ist für dich, wenn sqrt eine negative Zahl bekommt? Wie es aussieht, bist du in C++ genauso fit wie in Haskell. Also meine häufigsten Fehler in C++ lagen an falschen Schleifen, unüberschaubarer Vererbung, Zeigerprobleme, nicht oder zu früh freigegebene Resourcen, etc.

    Das liegt aber nur daran, daß Haskell viele Aspekte hinter den Kulissen abwickelt, die der C++ Entwickler direkte beeinflussen kann.

    Da bin ich ja mal gespannt. Zum Beispiel?

    Außerdem kannst du die falsche Verwendung von Datenypen in C++ genauso unterbinden wie in Haskell (ist nur ein wenig aufwendiger, aber machbar). Die meisten Laufzeitfehler, die mir in letzter Zeit untergekommen sind, basierten auf Rechen- oder Denkfehlern und Daten, die erst zur Laufzeit bekannt sind. Sowas kannst du nicht diagnostizieren indem du es in ein Typ-Korsett presst.

    Datentypen beziehen sich auf Werte. In Haskell fällt aber wesentlich mehr in die Klasse Werte als in C++. Funktionen etwa sind auch Werte und haben einen Typen. Kontrollstrukturen (Schleifen, sofern man sie braucht, Exceptions, sogar Labels und Sprünge) sind normale Werte und haben einen Typen. Die gesamte Programmlogik hat einen Typen. Rechenfehler werden nicht abgefangen, aber Denkfehler, die sich auf die Programmlogik beziehen, sehr wohl. Du hast referentielle Transparenz (Entsprechung in C++ wäre etwa: ist f(x) = 3, dann kannst du überall in deinem Programm den Aufruf f(x) durch das Ergebnis 3 ersetzen, ohne dein Programm zu verändern) und kannst durch lazy evaluation viele Algorithmen auf eine Art schreiben, die den Datenfluss expliziter und deshalb weniger fehleranfällig macht. Wie oft hat man ein falsches Ergebnis, weil man Zuweisungen in der falschen Reihenfolge geschrieben hat?

    Ich hab' den Shootout jetzt nicht im Detail analysiert, aber woher willst du wissen, wie gut die einzelnen Kandidaten tatsächlich optimiert worden sind?

    Indem ich sie mir ansehe?

    Klar, wenn man die Möglichkeiten einer Sprache einschränkt, kann man innerhalb dieser Möglichkeiten irgendwann alles beweisen. Das Problem ist, daß du mit einer solchen Sprache schneller an die Grenzen dessen kommst, was du darstellen kannst.

    Also ich weiß nicht. Ein komplettes HTTP-Framework gibt es bereits in Agda. Dieses Framework demonstriert auch schön, wie man in Agda all die schönen Sachen machen kann, die du willst, und die in Haskell nur sehr aufwendig zu realisieren sind.

    Du wolltest doch Fehlerfreiheit durch Typsicherheit ausdrücken (oder war das einer der anderen Haskell-Anhänger - jedenfalls kam von einem von euch die Aussage "wenn es sich compilieren lässt, ist es fehlerfrei"?).

    Meine Aussage war, dass ein Programm, das kompiliert, in den meisten Fällen auch funktioniert. Ich schreibe meine Programme so, dass ich nur selten Fehler zur Laufzeit finden muss. Und besonders viel Numerik kommt in meinen Programmen nicht vor, daher habe ich auch selten arithmetische Bugs. Die statisch zu prüfen würde aus einem effizienten 1000-Zeilen-Programm ein sehr ineffizientes, kaum zu überblickendes 100000-Zeilen-Programm machen. Das ist auch der Grund, warum ich dir keine Code-Beispiele gebe. Ich nehme mir nicht ein ganzes Wochenende Zeit, nur um dir zu beweisen, dass es möglich ist, auch solche Beweise zu führen.

    Außerdem habe ich dir nicht widersprochen, als du sagtest, dass Werte, die von außen reinkommen, auch zur Laufzeit geprüft werden müssen. Diese Prüfung besteht darin, etwa den hereinkommenden String richtig in die Konstruktoren des Datentyps zu verpacken, der den Wert in das statisch geprüfte System nimmt. Dafür brauchst du einen Algorithmus. Wenn dieser Algorithmus etwa eine Benutzereingabe in das x in sqrt(x - 1) einsetzt, dann muss er so geschrieben sein, dass statisch garantiert werden kann, dass x ≥ 1 gilt, ansonsten kompiliert er nicht. Den Aufwand dafür schätze ich auf 500-1000 Zeilen Code mit allem drum und dran. Vielleicht verstehst du jetzt, warum ich dir kein Code-Beispiel gebe, und warum ich ständig immer wieder betone, dass du dir lieber Agda als Haskell anschauen solltest, wenn du sowas willst.

    volkard schrieb:

    ertes schrieb:

    Haskell ist typensicher und Programme, die kompilieren, funktionieren meistens auch. Viele Bugs, die in C++ erst zur Laufzeit auftreten würden, fängt in Haskell bereits der Compiler ab. (Eure Interpretation: Ich würde meine Programme nie testen. Ich würde meine Programme so schreiben, dass jede noch so kleine Kleinigkeit statisch garantiert wird.)

    Das rührt aus einem Mißverständnis her.
    Jeder, der "Effektiv C++ programmieren" gelesen und verstanden hat, macht auch in C++ viele Bugs, die in vielen anderen Sprachen erst zur Laufzeit auftreten würden, zu Compilerfehlern. Wir versuchten zu ergründen, was Haskell da an Mehrwert hat. Und Du bliebst für uns enorm schwammig widersprüchlich leer, weil Du einerseits Codebeispiele gezeigt hast, die dann doch zu extrem waren und Du sie selber nicht verwendest, und andererseits Codebeispiele zeigtest, die verwendbar sind und auch in modernem C++ eine Selbstverständlichkeit sind. Es war kein Mehrwert ersichtlich, obwohl Du dauernd den Mehrwert betont hast. Verwirrend. Also fragt man nach. Und es kommt nur weiter *******.
    Wir gingen dummerweise davon aus, daß Du C++ total gut kannst. Weil Du es mehrfach behauptet hast. Ab jetzt spreche ich es auch Dir ab. Es gibt viele mehrjährige C++-Programmierer, die nicht gut sind. Es würde einfach gut erklären, warum Du Dich in Haskell so verknallt hast. Fröhliche Ostern!

    Siehe oben. Nur weil du meine Argumente nicht verstehst, brauchst du nicht mit persönlichen Angriffen loslegen. Das ist übrigens gemeinhin ein Hinweis dafür, dass dir selber die Argumente ausgehen.



  • ertes schrieb:

    Du bemerkst anscheinend gar nicht, wie du dir selber widerspichst. Auf der einen Seite sagst du, daß Haskell typische C++ Fehler zur Compilezeit abfangen kann, auf der anderen Seite kommt dann

    HASKELL IST DAFÜR NICHT GEEIGNET!

    Ein typischer C++-Fehler ist für dich, wenn sqrt eine negative Zahl bekommt? Wie es aussieht, bist du in C++ genauso fit wie in Haskell. Also meine häufigsten Fehler in C++ lagen an falschen Schleifen, unüberschaubarer Vererbung, Zeigerprobleme, nicht oder zu früh freigegebene Resourcen, etc.

    Das liegt aber nur daran, daß Haskell viele Aspekte hinter den Kulissen abwickelt, die der C++ Entwickler direkte beeinflussen kann.

    Da bin ich ja mal gespannt. Zum Beispiel?

    Die Beispiele hast du doch selber gerade genannt: In C++ kann man direkt mit dem Speicher hantieren, muß dann aber mit den Konsequenzen umgehen können. In C++ kann man seine Daten auch in vernünftige Container packen, die einem derartige Probleme dann abnehmen. In Haskell hast du den Vorteil, daß du von Haus aus von der Low-Level Speicherverwaltung abgekoppelt bist und sich schon ein schlauer Compiler-Entwickler um deren Risiken gekümmert hat.

    Um mal weg von der Arithmetik zu kommen (ist dir wohl ohnehin zu abstrakt), ein typischeres Problem in C++ sind ungültige Indizes. Ich kann in beiden Sprachen eine Funktion schreiben, die mir das n-te Element einer Liste liefert - und die werden in beiden Sprachen Probleme bekommen, wenn ich einen Index jenseits der Listen-Größe angebe. Wie sich diese Probleme äußern, mag jetzt unterschiedlich sein, aber auf jeden Fall brauche ich Code, der zur Laufzeit damit umgehen kann.
    Du kannst jetzt gerne einwenden, daß du den drumherumliegenden Algorithmus so anpassen kannst daß der Fall nicht vorkommt - aber ich kann das genausogut in C++ 😉

    Außerdem kannst du die falsche Verwendung von Datenypen in C++ genauso unterbinden wie in Haskell (ist nur ein wenig aufwendiger, aber machbar). Die meisten Laufzeitfehler, die mir in letzter Zeit untergekommen sind, basierten auf Rechen- oder Denkfehlern und Daten, die erst zur Laufzeit bekannt sind. Sowas kannst du nicht diagnostizieren indem du es in ein Typ-Korsett presst.

    Datentypen beziehen sich auf Werte. In Haskell fällt aber wesentlich mehr in die Klasse Werte als in C++. Funktionen etwa sind auch Werte und haben einen Typen. Kontrollstrukturen (Schleifen, sofern man sie braucht, Exceptions, sogar Labels und Sprünge) sind normale Werte und haben einen Typen. Die gesamte Programmlogik hat einen Typen. Rechenfehler werden nicht abgefangen, aber Denkfehler, die sich auf die Programmlogik beziehen, sehr wohl. Du hast referentielle Transparenz (Entsprechung in C++ wäre etwa: ist f(x) = 3, dann kannst du überall in deinem Programm den Aufruf f(x) durch das Ergebnis 3 ersetzen, ohne dein Programm zu verändern) und kannst durch lazy evaluation viele Algorithmen auf eine Art schreiben, die den Datenfluss expliziter und deshalb weniger fehleranfällig macht. Wie oft hat man ein falsches Ergebnis, weil man Zuweisungen in der falschen Reihenfolge geschrieben hat?

    kommt bei mir eher seltener vor.

    Daß man Funktionen auch wieder als Werte betrachten kann, ist vielleicht ein Vorteil (wobei C++ auch Funktionszeiger und Funktoren anbietet), daß man Kontrollstrukturen auch als Werte ansehen kann, liegt vermutlich am Konzept der funktionalen Programmierung. Und referenzielle Transparenz habe ich auch noch nicht wirklich benötigt - wenn es mir zu umständlich ist, den Wert von f(x) an mehreren Stellen im Programm ausrechnen zu lassen, packe ich ihn halt in eine Hilfsvariable.

    Klar, wenn man die Möglichkeiten einer Sprache einschränkt, kann man innerhalb dieser Möglichkeiten irgendwann alles beweisen. Das Problem ist, daß du mit einer solchen Sprache schneller an die Grenzen dessen kommst, was du darstellen kannst.

    Also ich weiß nicht. Ein komplettes HTTP-Framework gibt es bereits in Agda. Dieses Framework demonstriert auch schön, wie man in Agda all die schönen Sachen machen kann, die du willst, und die in Haskell nur sehr aufwendig zu realisieren sind.

    Es ist kein Problem, für einen speziellen Anwendungsbereich eine nicht-turingvollständige Sprache zu verwenden, solange es für das reicht, was du damit vorhast. Und zu deinem Glück fallen mir aus dem Stegreif auch nur akademische Beispiele ein, die die Grenzen der Tuing-Vollständigkeit ausnutzen und mit so einer "verkleinerten" Sprache nicht lösbar wären.

    Du wolltest doch Fehlerfreiheit durch Typsicherheit ausdrücken (oder war das einer der anderen Haskell-Anhänger - jedenfalls kam von einem von euch die Aussage "wenn es sich compilieren lässt, ist es fehlerfrei"?).

    Meine Aussage war, dass ein Programm, das kompiliert, in den meisten Fällen auch funktioniert. Ich schreibe meine Programme so, dass ich nur selten Fehler zur Laufzeit finden muss. Und besonders viel Numerik kommt in meinen Programmen nicht vor, daher habe ich auch selten arithmetische Bugs. Die statisch zu prüfen würde aus einem effizienten 1000-Zeilen-Programm ein sehr ineffizientes, kaum zu überblickendes 100000-Zeilen-Programm machen. Das ist auch der Grund, warum ich dir keine Code-Beispiele gebe. Ich nehme mir nicht ein ganzes Wochenende Zeit, nur um dir zu beweisen, dass es möglich ist, auch solche Beweise zu führen.

    Darf man erfahren, was für Programme du so schreibst, bei denen du ohne Arithmetik auskommst? Ich habe beruflich mit Anwendungen zu tun, die einiges zu rechnen, vergleichen und auszuwerten haben, also beschäftige ich mich naturgemäß ein wenig stärker mit dem arithmetischen Aspekt.

    volkard schrieb:

    ertes schrieb:

    Haskell ist typensicher und Programme, die kompilieren, funktionieren meistens auch. Viele Bugs, die in C++ erst zur Laufzeit auftreten würden, fängt in Haskell bereits der Compiler ab. (Eure Interpretation: Ich würde meine Programme nie testen. Ich würde meine Programme so schreiben, dass jede noch so kleine Kleinigkeit statisch garantiert wird.)

    Das rührt aus einem Mißverständnis her.
    Jeder, der "Effektiv C++ programmieren" gelesen und verstanden hat, macht auch in C++ viele Bugs, die in vielen anderen Sprachen erst zur Laufzeit auftreten würden, zu Compilerfehlern. Wir versuchten zu ergründen, was Haskell da an Mehrwert hat. Und Du bliebst für uns enorm schwammig widersprüchlich leer, weil Du einerseits Codebeispiele gezeigt hast, die dann doch zu extrem waren und Du sie selber nicht verwendest, und andererseits Codebeispiele zeigtest, die verwendbar sind und auch in modernem C++ eine Selbstverständlichkeit sind. Es war kein Mehrwert ersichtlich, obwohl Du dauernd den Mehrwert betont hast. Verwirrend. Also fragt man nach. Und es kommt nur weiter *******.
    Wir gingen dummerweise davon aus, daß Du C++ total gut kannst. Weil Du es mehrfach behauptet hast. Ab jetzt spreche ich es auch Dir ab. Es gibt viele mehrjährige C++-Programmierer, die nicht gut sind. Es würde einfach gut erklären, warum Du Dich in Haskell so verknallt hast. Fröhliche Ostern!

    Siehe oben. Nur weil du meine Argumente nicht verstehst, brauchst du nicht mit persönlichen Angriffen loslegen. Das ist übrigens gemeinhin ein Hinweis dafür, dass dir selber die Argumente ausgehen.

    Die Tatsache, daß du ständig die selben Thesen wiederholst, kann man auch als Hinweis ansehen, daß dir die Argumente ausgehen.



  • ertes schrieb:

    HALLO, KANNST DU LESEN ODER WAS?

    ertes schrieb:

    Entweder du bist wirklich strohdumm

    ertes schrieb:

    Nur weil du meine Argumente nicht verstehst, brauchst du nicht mit persönlichen Angriffen loslegen. Das ist übrigens gemeinhin ein Hinweis dafür, dass dir selber die Argumente ausgehen.

    LOL 🤡



  • CStoll schrieb:

    ertes schrieb:

    Das liegt aber nur daran, daß Haskell viele Aspekte hinter den Kulissen abwickelt, die der C++ Entwickler direkte beeinflussen kann.

    Da bin ich ja mal gespannt. Zum Beispiel?

    Die Beispiele hast du doch selber gerade genannt: In C++ kann man direkt mit dem Speicher hantieren, muß dann aber mit den Konsequenzen umgehen können. In C++ kann man seine Daten auch in vernünftige Container packen, die einem derartige Probleme dann abnehmen. In Haskell hast du den Vorteil, daß du von Haus aus von der Low-Level Speicherverwaltung abgekoppelt bist und sich schon ein schlauer Compiler-Entwickler um deren Risiken gekümmert hat.

    Zeiger, "vernünftige Container" (also effiziente Container durch Allokierung und direkte Manipulation von Speicher) und die damit verbundenen Probleme gibt es in Haskell auch (siehe Foreign.*), wenn man möchte. Die gängigen, schnellen Datenstrukturen verwenden teilweise diese Möglichkeit. Haskell ist eine Programmiersprache, kein Algebrasystem.

    Um mal weg von der Arithmetik zu kommen (ist dir wohl ohnehin zu abstrakt), ein typischeres Problem in C++ sind ungültige Indizes. Ich kann in beiden Sprachen eine Funktion schreiben, die mir das n-te Element einer Liste liefert - und die werden in beiden Sprachen Probleme bekommen, wenn ich einen Index jenseits der Listen-Größe angebe. Wie sich diese Probleme äußern, mag jetzt unterschiedlich sein, aber auf jeden Fall brauche ich Code, der zur Laufzeit damit umgehen kann.
    Du kannst jetzt gerne einwenden, daß du den drumherumliegenden Algorithmus so anpassen kannst daß der Fall nicht vorkommt - aber ich kann das genausogut in C++ 😉

    Sowas kann man statisch prüfen. Was man dafür braucht, sind sog. dependent types. Die gibt es in Haskell zwar nicht, aber man kann mit ein paar Typentricks diese bis zu einem gewissen Grad simulieren. Das bedeutet, man bekommt Arrays mit statischen Längengarantien, sodass man keinen Laufzeitaufwand mehr hat.

    Daß man Funktionen auch wieder als Werte betrachten kann, ist vielleicht ein Vorteil (wobei C++ auch Funktionszeiger und Funktoren anbietet), daß man Kontrollstrukturen auch als Werte ansehen kann, liegt vermutlich am Konzept der funktionalen Programmierung. Und referenzielle Transparenz habe ich auch noch nicht wirklich benötigt - wenn es mir zu umständlich ist, den Wert von f(x) an mehreren Stellen im Programm ausrechnen zu lassen, packe ich ihn halt in eine Hilfsvariable.

    Niemand benötigt referentielle Transparenz, ebensowenig wie irgendjemand Hochsprachen benötigt. Sie hat übrigens auch wenig mit Optimierung zu tun, obwohl sie dafür auch genutzt werden kann. Das (also CSE) macht GHC allerdings bewusst nicht, weil das die Semantik der Sprache beeinflusst. Hintergrund ist, dass es unentscheidbar ist, ob das Programm durch die Optimierung weniger oder mehr Speicher braucht. Wenn man einen berechneten Wert wiederverwenden will, sollte man ihm einen Namen geben (in Haskell).

    Es ist kein Problem, für einen speziellen Anwendungsbereich eine nicht-turingvollständige Sprache zu verwenden, solange es für das reicht, was du damit vorhast. Und zu deinem Glück fallen mir aus dem Stegreif auch nur akademische Beispiele ein, die die Grenzen der Tuing-Vollständigkeit ausnutzen und mit so einer "verkleinerten" Sprache nicht lösbar wären.

    Agda ist allerdings als Allzwecksprache gedacht, mit Schwerpunkt auf Beweisführung.

    Darf man erfahren, was für Programme du so schreibst, bei denen du ohne Arithmetik auskommst? Ich habe beruflich mit Anwendungen zu tun, die einiges zu rechnen, vergleichen und auszuwerten haben, also beschäftige ich mich naturgemäß ein wenig stärker mit dem arithmetischen Aspekt.

    Hauptsächlich verarbeite ich Daten. Entgegennehmen, prüfen, speichern, abrufen, etc. Server und Weboberflächen. Ganz ohne (expliziter) Arithmetik komme ich natürlich nicht aus, aber viel habe ich da nicht. Das ist so die Durchschnittsanwendung, die ich schreibe.

    Die Tatsache, daß du ständig die selben Thesen wiederholst, kann man auch als Hinweis ansehen, daß dir die Argumente ausgehen.

    Diese "Thesen" sind meine Argumente.

    cooky451 schrieb:

    ertes schrieb:

    HALLO, KANNST DU LESEN ODER WAS?

    ertes schrieb:

    Entweder du bist wirklich strohdumm

    ertes schrieb:

    Nur weil du meine Argumente nicht verstehst, brauchst du nicht mit persönlichen Angriffen loslegen. Das ist übrigens gemeinhin ein Hinweis dafür, dass dir selber die Argumente ausgehen.

    LOL 🤡

    Man kann die Tatsachen immer verschleiern, wenn man unvollständig zitiert oder die Bedeutung des Fragezeichens nicht versteht. 😉 Außerdem bleibt meine Aussage davon unbetroffen.



  • ertes schrieb:

    CStoll schrieb:

    ertes schrieb:

    Das liegt aber nur daran, daß Haskell viele Aspekte hinter den Kulissen abwickelt, die der C++ Entwickler direkte beeinflussen kann.

    Da bin ich ja mal gespannt. Zum Beispiel?

    Die Beispiele hast du doch selber gerade genannt: In C++ kann man direkt mit dem Speicher hantieren, muß dann aber mit den Konsequenzen umgehen können. In C++ kann man seine Daten auch in vernünftige Container packen, die einem derartige Probleme dann abnehmen. In Haskell hast du den Vorteil, daß du von Haus aus von der Low-Level Speicherverwaltung abgekoppelt bist und sich schon ein schlauer Compiler-Entwickler um deren Risiken gekümmert hat.

    Zeiger, "vernünftige Container" (also effiziente Container durch Allokierung und direkte Manipulation von Speicher) und die damit verbundenen Probleme gibt es in Haskell auch (siehe Foreign.*), wenn man möchte. Die gängigen, schnellen Datenstrukturen verwenden teilweise diese Möglichkeit. Haskell ist eine Programmiersprache, kein Algebrasystem.

    Liest du überhaupt deine eigenen Beiträge? Ich hab' nämlich langsam das Gefühl, daß wir aneinander vorbeireden.
    Nochmal langsam zum Mitschreiben:
    In C++ kann man viele Dummheiten machen, wenn man tief genug eintaucht (und leider gibt es noch zu viele Programmierer, die nur diesen Stil kennengelernt haben). Aber in C++ gibt es auch genug Möglichkeiten, richtig und fehlersicher zu programmieren (volkard hatte schon "Effektiv C++ programmieren" als Referenz dafür genannt). Aber das erfordert natürlich ein paar Kenntnisse und Disziplin.
    In Haskell sind die High-Level Funktionen vermutlich einfacher anzuwenden und werden deshalb eher genutzt, während Low-Level mit Mehraufwand verbunden ist. Darum gibt es vermutlich mehr "gute" Haskell-Programmierer als "gute" C++ Programmierer.

    Um mal weg von der Arithmetik zu kommen (ist dir wohl ohnehin zu abstrakt), ein typischeres Problem in C++ sind ungültige Indizes. Ich kann in beiden Sprachen eine Funktion schreiben, die mir das n-te Element einer Liste liefert - und die werden in beiden Sprachen Probleme bekommen, wenn ich einen Index jenseits der Listen-Größe angebe. Wie sich diese Probleme äußern, mag jetzt unterschiedlich sein, aber auf jeden Fall brauche ich Code, der zur Laufzeit damit umgehen kann.
    Du kannst jetzt gerne einwenden, daß du den drumherumliegenden Algorithmus so anpassen kannst daß der Fall nicht vorkommt - aber ich kann das genausogut in C++ 😉

    Sowas kann man statisch prüfen. Was man dafür braucht, sind sog. dependent types. Die gibt es in Haskell zwar nicht, aber man kann mit ein paar Typentricks diese bis zu einem gewissen Grad simulieren. Das bedeutet, man bekommt Arrays mit statischen Längengarantien, sodass man keinen Laufzeitaufwand mehr hat.

    Arrays mit statischen Längengarantien kann man auch mit C++ aufbauen, deswegen muß der Nutzer dieses Arrays trotzdem sicherstellen, daß keine ungültigen Indizes übergeben werden. Der einzige Unterschied besteht da in der Art der Fehlerbehandlung durch den Anwender dieses Arrays.

    Daß man Funktionen auch wieder als Werte betrachten kann, ist vielleicht ein Vorteil (wobei C++ auch Funktionszeiger und Funktoren anbietet), daß man Kontrollstrukturen auch als Werte ansehen kann, liegt vermutlich am Konzept der funktionalen Programmierung. Und referenzielle Transparenz habe ich auch noch nicht wirklich benötigt - wenn es mir zu umständlich ist, den Wert von f(x) an mehreren Stellen im Programm ausrechnen zu lassen, packe ich ihn halt in eine Hilfsvariable.

    Niemand benötigt referentielle Transparenz, ebensowenig wie irgendjemand Hochsprachen benötigt. Sie hat übrigens auch wenig mit Optimierung zu tun, obwohl sie dafür auch genutzt werden kann. Das (also CSE) macht GHC allerdings bewusst nicht, weil das die Semantik der Sprache beeinflusst. Hintergrund ist, dass es unentscheidbar ist, ob das Programm durch die Optimierung weniger oder mehr Speicher braucht. Wenn man einen berechneten Wert wiederverwenden will, sollte man ihm einen Namen geben (in Haskell).

    Wenn es niemand benötigt, wieso preist du es dann als großen Vorteil an?

    Es ist kein Problem, für einen speziellen Anwendungsbereich eine nicht-turingvollständige Sprache zu verwenden, solange es für das reicht, was du damit vorhast. Und zu deinem Glück fallen mir aus dem Stegreif auch nur akademische Beispiele ein, die die Grenzen der Tuing-Vollständigkeit ausnutzen und mit so einer "verkleinerten" Sprache nicht lösbar wären.

    Agda ist allerdings als Allzwecksprache gedacht, mit Schwerpunkt auf Beweisführung.

    Und was willst du damit jetzt aussagen?

    Die Tatsache, daß du ständig die selben Thesen wiederholst, kann man auch als Hinweis ansehen, daß dir die Argumente ausgehen.

    Diese "Thesen" sind meine Argumente.

    Das ist noch lange kein Grund, sie immer wieder zu wiederholen. Durch Wiederholung werden deine Aussagen auch nicht besser, wenn du sie nicht weiter untermauern kannst.



  • CStoll schrieb:

    Arrays mit statischen Längengarantien kann man auch mit C++ aufbauen, deswegen muß der Nutzer dieses Arrays trotzdem sicherstellen, daß keine ungültigen Indizes übergeben werden. Der einzige Unterschied besteht da in der Art der Fehlerbehandlung durch den Anwender dieses Arrays.

    Est es auch kein Problem, einen Index-Typ dafür zu bauen, der zur Laufzeit(!) prüft, ob die arithmetischen Operationen erlaubt sind und gültige Indizes für das Array ergeben. Und jetzt kommt verwendete der Trick vom verlinkten Code:
    Die Funktion mitte(a,b){return a+(b-a)/2;} braucht KEINE Laufzeitüberprüfung, das Ergebis ist immer ein sicherer Index, wenn a und b sichere Indizes waren. Damit läßt sich die binäre Suche OHNE Laufzeitprüfung machen.
    Ich kann's mir nicht verkneifen: 🤡

    ps: Die haben (a+b)/2 benutzt und haben keine Angst vor einem Überlauf.



  • volkard schrieb:

    CStoll schrieb:

    Arrays mit statischen Längengarantien kann man auch mit C++ aufbauen, deswegen muß der Nutzer dieses Arrays trotzdem sicherstellen, daß keine ungültigen Indizes übergeben werden. Der einzige Unterschied besteht da in der Art der Fehlerbehandlung durch den Anwender dieses Arrays.

    Wenn die Arraygröße Comilezeitkonstant ist, ist es auch kein Problem, einen Index-Typ dafür zu bauen, der zur Laufzeit(!) prüft, ob die arithmetischen Operationen erlaubt sind. Und jetzt kommt verwendete der Trick vom verlinkten Code:
    Die Funktion mitte(a,b){return a+(b-a)/2;} braucht KEINE Laufzeitüberprüfung, das Ergebis ist immer ein sicherer Index, wenn a und b sichere Indizes waren. Damit läßt sich die binäre Suche OHNE Laufzeitprüfung machen.
    Ich kann's mir nicht verkneifen: 🤡

    Das kann ich auch, ich brauche dafür nur einen eigenen Index-Typ und entsprechende Operator-/Funktions-Überladungen.



  • CStoll schrieb:

    Liest du überhaupt deine eigenen Beiträge? Ich hab' nämlich langsam das Gefühl, daß wir aneinander vorbeireden.

    Ätsch das macht ihr schon die ganze Zeit, deswegen wunder es mich, dass hier dieser Quatsch weitergemacht wird.

    Auf der eine Seite ist CStoll kann auch theoretisch und konzeptionell über Programmiersprachen reden und auf der Andere Ertes, der nur exemplarisch an Haskell Konzepte erläutern kann mit ein Hauch von Validation/Verifikation(welches Wort ist Richtig)?-System-Know-How.

    Das ist mein Eindruck.



  • Validierung oder Verifikation. Nur weil du gefragt hast 🤡



  • Da der Thread grad passt, ich bin grad dabei ein wenig Haskell zu lernen, und gewöhne mich grad an den Pattern-Matching-Mechanismus.
    Jetzt würde ich gerne eine equals-Funktion (bzw. etwas ähnliches) umsetzen. Ich hätte gehofft, dass Folgendes funktioniert:

    eq :: a -> Bool
    eq n n = True
    eq n m = False
    

    Quasi wie man es aus der Mathematik kennt. Funktioniert das irgendwie und ich habs übersehen, oder muss ich das mit

    eq :: a -> Bool
    eq n m = (n == m)
    

    o.ä. machen?

    Schönen Abend noch.



  • Meines Wissen (und meiner flüchtigen Versuche gerade) geht das nicht. Ganz davon abgesehen ist der Typ aber auch falsch.
    Richtig ist:

    eq :: Eq a => a -> a -> Bool
    eq a b = a == b
    


  • CStoll schrieb:

    Liest du überhaupt deine eigenen Beiträge?

    Ja.

    Ich hab' nämlich langsam das Gefühl, daß wir aneinander vorbeireden.

    Endlich hast du es begriffen. Du verlangst ständig von mir, dass ich Haskell-Features verteidige, die ich überhaupt niemals angepriesen habe, und die Features, die ich angepriesen habe, ignorierst du völlig, und zwar bis einschließlich jetzt. C++ ist keinen Deut besser bei den Features, die du diskutierst und um Längen schlechter bei den Features, die ich wirklich anpreise. Kein Wunder, dass du als C++-Jünger nicht darauf eingehst.

    Nochmal langsam zum Mitschreiben:
    In C++ kann man viele Dummheiten machen, wenn man tief genug eintaucht (und leider gibt es noch zu viele Programmierer, die nur diesen Stil kennengelernt haben). Aber in C++ gibt es auch genug Möglichkeiten, richtig und fehlersicher zu programmieren (volkard hatte schon "Effektiv C++ programmieren" als Referenz dafür genannt). Aber das erfordert natürlich ein paar Kenntnisse und Disziplin.

    In C++ muss eine Bibliothek eben die Garantien erbringen, die in Haskell die Sprache selbst erbringen kann.

    In Haskell sind die High-Level Funktionen vermutlich einfacher anzuwenden und werden deshalb eher genutzt, während Low-Level mit Mehraufwand verbunden ist. Darum gibt es vermutlich mehr "gute" Haskell-Programmierer als "gute" C++ Programmierer.

    Falsch. Low-Level-Funktionen sind in Haskell genauso anzuwenden wie in C++ auch, wahrscheinlich sogar noch leichter. Allerdings hat man da eben Funktionen und Kombinatoren mit richtigen Namen statt symbolische Operatoren (die im Endeffekt auch nur Funktionen sind). Das heißt, Haskell bringt auch die guten alten peek und poke wieder zurück. Daher entsteht oft der Eindruck, dass Haskell nicht so gut für Low-Level-Programmierung geeignet sei.

    Niemand benötigt referentielle Transparenz, ebensowenig wie irgendjemand Hochsprachen benötigt. Sie hat übrigens auch wenig mit Optimierung zu tun, obwohl sie dafür auch genutzt werden kann. Das (also CSE) macht GHC allerdings bewusst nicht, weil das die Semantik der Sprache beeinflusst. Hintergrund ist, dass es unentscheidbar ist, ob das Programm durch die Optimierung weniger oder mehr Speicher braucht. Wenn man einen berechneten Wert wiederverwenden will, sollte man ihm einen Namen geben (in Haskell).

    Wenn es niemand benötigt, wieso preist du es dann als großen Vorteil an?

    Also wenn du die Aussage nicht verstanden hast, hast du dir selber ein Armutszeugnis erteilt. Sorry, dass ich jetzt mit dir wie mit einem Drittklässler rede, aber niemand braucht referentielle Transparent. Niemand braucht überhaupt Programmiersprachen. Es geht schließlich auch mit Lochkarten. Mit anderen Worten: Dass du referentielle Transparenz noch nie gebraucht hast ist eine Aussage wie, "der Himmel ist blau". Ich habe sie auch nie gebraucht.

    Agda ist allerdings als Allzwecksprache gedacht, mit Schwerpunkt auf Beweisführung.

    Und was willst du damit jetzt aussagen?

    Dass du mit Agda jede Art von Programm schreiben kannst. Turing-Unvollständigkeit schränkt den Einsatzbereich einer Sprache nicht im Geringsten ein.

    Das ist noch lange kein Grund, sie immer wieder zu wiederholen. Durch Wiederholung werden deine Aussagen auch nicht besser, wenn du sie nicht weiter untermauern kannst.

    Wie soll ich sie denn hier noch weiter untermauern? Meine Aussagen habe ich mit echten Code-Beispielen untermauert. Und damit meine ich nicht Aussagen, die du mir unterstellst, sondern die ich wirklich gemacht habe. Und meine Aussagen stehen unangefochten immer noch im Raum. Bisher ist immer noch keiner auf meine Aussagen eingegangen. Bisher hat mir keiner einen Vorteil von C++ gegenüber Haskell genannt, sondern immer nur: "Kann C++ doch auch!". Es gibt also schon mal ein paar Dinge, die C++ genauso gut kann wie Haskell – streite ich nicht ab.

    Ich habe aber Dinge genannt, die Haskell wesentlich besser kann als C++. Null Reaktion von den C++-Gläubigen. Klar, warum auch? Ohne Gegenbeispiele müsste man ja zugeben, dass C++ schlechter ist. Warum? C++ kann nichts besser als Haskell, aber Haskell kann vieles besser als C++.

    volkard schrieb:

    CStoll schrieb:

    Arrays mit statischen Längengarantien kann man auch mit C++ aufbauen, deswegen muß der Nutzer dieses Arrays trotzdem sicherstellen, daß keine ungültigen Indizes übergeben werden. Der einzige Unterschied besteht da in der Art der Fehlerbehandlung durch den Anwender dieses Arrays.

    Est es auch kein Problem, einen Index-Typ dafür zu bauen, der zur Laufzeit(!) prüft, ob die arithmetischen Operationen erlaubt sind und gültige Indizes für das Array ergeben. Und jetzt kommt verwendete der Trick vom verlinkten Code:
    Die Funktion mitte(a,b){return a+(b-a)/2;} braucht KEINE Laufzeitüberprüfung, das Ergebis ist immer ein sicherer Index, wenn a und b sichere Indizes waren. Damit läßt sich die binäre Suche OHNE Laufzeitprüfung machen.

    Was genau habt ihr an dem Wort "statisch" nicht verstanden? Das ist keine statische Prüfung, sondern eine Optimierung.

    Zeus schrieb:

    Auf der eine Seite ist CStoll kann auch theoretisch und konzeptionell über Programmiersprachen reden und auf der Andere Ertes, der nur exemplarisch an Haskell Konzepte erläutern kann mit ein Hauch von Validation/Verifikation(welches Wort ist Richtig)?-System-Know-How.

    Nein, CStoll kann eben nicht theoretisch und konzeptionell über Programmiersprachen reden. Das ist ja das Problem; deswegen exemplarisch. Wenn ich anfangen würde mit Typentheorie, würde er gar nichts mehr verstehen und mir noch mehr Blödsinn unterstellen. Mir wurde ja schon mal vorgeworfen, ich würde nur mit Fachbegriffen um mich werfen.

    jungerjünger schrieb:

    eq :: a -> Bool
    

    Der Typ ergibt wenig Sinn für eine Vergleichsfunktion. Die einzige Funktion, die du damit schreiben kannst, ist eine konstante Funktion, etwa: eq = const True. Das liegt daran, dass du über den Typen a alleine nichts weißt. Du brauchst mehr Kontext, z.B. so, wie es ipsec beschrieben hat:

    eq :: Eq aaa → Bool
    eq = (==)



  • Das mit dem Typen hat mir der GHC auch gleich um die Ohren geschleudert. Darauf wollte ich aber nicht hinaus, sondern nur, ob man irgendwie durch Parameternamen Gleichheit von Parametern implizieren kann.



  • ertes schrieb:

    Nochmal langsam zum Mitschreiben:
    In C++ kann man viele Dummheiten machen, wenn man tief genug eintaucht (und leider gibt es noch zu viele Programmierer, die nur diesen Stil kennengelernt haben). Aber in C++ gibt es auch genug Möglichkeiten, richtig und fehlersicher zu programmieren (volkard hatte schon "Effektiv C++ programmieren" als Referenz dafür genannt). Aber das erfordert natürlich ein paar Kenntnisse und Disziplin.

    In C++ muss eine Bibliothek eben die Garantien erbringen, die in Haskell die Sprache selbst erbringen kann.

    In Haskell sind die High-Level Funktionen vermutlich einfacher anzuwenden und werden deshalb eher genutzt, während Low-Level mit Mehraufwand verbunden ist. Darum gibt es vermutlich mehr "gute" Haskell-Programmierer als "gute" C++ Programmierer.

    Falsch. Low-Level-Funktionen sind in Haskell genauso anzuwenden wie in C++ auch, wahrscheinlich sogar noch leichter. Allerdings hat man da eben Funktionen und Kombinatoren mit richtigen Namen statt symbolische Operatoren (die im Endeffekt auch nur Funktionen sind). Das heißt, Haskell bringt auch die guten alten peek und poke wieder zurück. Daher entsteht oft der Eindruck, dass Haskell nicht so gut für Low-Level-Programmierung geeignet sei.

    Dann ist die Fehlersicherheit wohl eher eine Frage der Didaktik als der Sprache: Haskell-Anfänger lernen erst die sicheren WEge und dann die Dummheiten, C++-Anfänger (leider) genau umgekehrt (ich gehe hier nicht näher auf JW ein)

    Also wenn du die Aussage nicht verstanden hast, hast du dir selber ein Armutszeugnis erteilt. Sorry, dass ich jetzt mit dir wie mit einem Drittklässler rede, aber niemand braucht referentielle Transparent. Niemand braucht überhaupt Programmiersprachen. Es geht schließlich auch mit Lochkarten. Mit anderen Worten: Dass du referentielle Transparenz noch nie gebraucht hast ist eine Aussage wie, "der Himmel ist blau". Ich habe sie auch nie gebraucht.

    OK, dann erklär mir doch mal, welchen Vorteil ich daraus ziehen kann, daß ich referentielle Transparenz nutzen kann. Wird mein Programm schneller, wenn ich weiß, daß f(x) immer den selben Wert zurückliefert? Du hast selber gesagt, daß der Haskell-Compiler sowas nicht aus eigenem Antrieb optimiert - und eine Hilfsvariable für den Wert von f(x) anlegen zu können ist nicht an die Sprache gebunden.

    Agda ist allerdings als Allzwecksprache gedacht, mit Schwerpunkt auf Beweisführung.

    Und was willst du damit jetzt aussagen?

    Dass du mit Agda jede Art von Programm schreiben kannst. Turing-Unvollständigkeit schränkt den Einsatzbereich einer Sprache nicht im Geringsten ein.

    Wie gesagt, mir fallen gerade keine praktisch relevanten turing-vollständigen Probleme ein, aber das heißt nicht, daß es sie nicht gibt.

    Ich habe aber Dinge genannt, die Haskell wesentlich besser kann als C++. Null Reaktion von den C++-Gläubigen. Klar, warum auch? Ohne Gegenbeispiele müsste man ja zugeben, dass C++ schlechter ist. Warum? C++ kann nichts besser als Haskell, aber Haskell kann vieles besser als C++.

    Ich fürchte, bei deinen ganzen Beiträgen habe ich den Überblick verloren: Welche echten Vorteile von Haskell hast du denn genannt? Nach 23 Seiten blicke ich auch nicht mehr durch, was von deinen Beiträgen jetzt einen Haskell-Vorteil erklärt hat und was nur meine Aussagen als Unsinn hinstellen wollte.
    (wobei ich dazusagen muß, daß ich nicht genug von Haskell weiß, um seine Nachteile gegenüber C++ auf einen Blick zu erfassen)

    OK, die drei Punkte aus deiner letzten Auflistung:
    - typsicher: kann C++ auch
    - wenn es kompiliert, funktioniert es auch: halte ich immr noch für fragwürdig
    - besser für Web-Anwendungen: eine Zange ist auch besser zum Nägel in die Wand schlagen als ein Schraubendreher - trotzdem nimmt man dafür einen Hammer
    - vergleichbar in der Performance: ist für mich kein Kriterium, egal für welche Seite

    Nein, CStoll kann eben nicht theoretisch und konzeptionell über Programmiersprachen reden. Das ist ja das Problem; deswegen exemplarisch. Wenn ich anfangen würde mit Typentheorie, würde er gar nichts mehr verstehen und mir noch mehr Blödsinn unterstellen. Mir wurde ja schon mal vorgeworfen, ich würde nur mit Fachbegriffen um mich werfen.

    Versuch's doch.



  • ertes schrieb:

    volkard schrieb:

    CStoll schrieb:

    Arrays mit statischen Längengarantien kann man auch mit C++ aufbauen, deswegen muß der Nutzer dieses Arrays trotzdem sicherstellen, daß keine ungültigen Indizes übergeben werden. Der einzige Unterschied besteht da in der Art der Fehlerbehandlung durch den Anwender dieses Arrays.

    Est es auch kein Problem, einen Index-Typ dafür zu bauen, der zur Laufzeit(!) prüft, ob die arithmetischen Operationen erlaubt sind und gültige Indizes für das Array ergeben. Und jetzt kommt verwendete der Trick vom verlinkten Code:
    Die Funktion mitte(a,b){return a+(b-a)/2;} braucht KEINE Laufzeitüberprüfung, das Ergebis ist immer ein sicherer Index, wenn a und b sichere Indizes waren. Damit läßt sich die binäre Suche OHNE Laufzeitprüfung machen.

    Was genau habt ihr an dem Wort "statisch" nicht verstanden? Das ist keine statische Prüfung, sondern eine Optimierung.

    Was ich beschrieben habe, ist statisch und entspricht dem Artikel.

    Die andere Kritik kann ich zurückwerfen, Du ignorierst alles, was Du nicht sofort vestehst, und wiederholst längst widerlegte Argumente (hast die Widerlegung ja nicht verstanden). Wenn wir Dir nicht mehr antworten, liegt es nicht daran, daß Du überlegene Argumente wiederholt hättest, sondern an der Zwecklosigkeit einer Diskussion mit Dir.



  • Ich muss sagen, ich hab mich jetzt (auch aufgrund dieses Threads) endlich mal näher mit Haskell beschäftigt. Ich persönlich finde Haskell eine sehr schöne Sprache mit interessanten Konzepten. Von den funktionalen Sprachen hatte ich bisher nur Kontakt mit Lisp, Haskell spricht mich dabei mehr an.

    Eine direkte Konkurrenz von C++ und Haskell sehe ich aber nicht, die Anwendungsgebiete überschneiden sich nur zum Teil. Auch denke ich nicht, dass Haskell die Allheillösung ist, auf die alle Programmierer gewartet haben (wie man das in manche Posts dieses Threads reininterpretieren könnte - Haskell-Jünger gibt es eben genau so wie C++-Jünger).

    Eine direkte Kritik an Haskell habe ich aber. Bei vielen Beispielen, die ich sehe, wird denke ich mit der Eleganz übertrieben.
    Zum Beispiel hatte ich neulich diese Funktion bei Wikipedia gelesen:

    mf = (. map) . (.) . filter
    

    Das ist eine Point-Free-Implementierung von

    mf criteria operator list = filter criteria (map operator list)
    

    Die 2. Version finde ich sehr verständlich, bei der 1. bekomme ich immer noch ne Schraube im Kopf. An die Haskell-Experten: gibt es eine spezielle Technik, wie man solche Definitionen liest, oder ist das wirklich nur eine Sache der Erfahrung? Wer hätte mit der ersten Version spontan etwas anfangen können?
    Auf jeden Fall erschließt sich mir nicht, warum jemand überhaupt auf die Idee kommt, solche Funktionen zu schreiben (also in der 1. Version). Böse betrachtet ist das reine Eleganzgeilheit wer das abstrakteste Programm schreibt.

    Solche extremen Beispiele sind natürlich selten, allerdings muss ich oft mehrmals nachdenken, was denn eine Funktion jetzt eigentlich macht, während sehr oft auch verständlichere Beschreibungen möglich wären. Das ist natürlich nicht direkt Schuld von Haskell, sondern eher der Programmierer. Ich behaupte aber, dass mir sowas in C++ nicht passiert. Es mag an meiner größeren C++-Erfahrung liegen, aber auch weil C++ solche extrem abstrakten Konstrukte nicht so leicht möglich macht wie Haskell.

    Übrigens eine interessante Äußerung in einer Diskussion (indirekt) dazu:

    > You can use flip as a "wildcard" aswell:

    > listeEtagTot = concatMap (listeEtagArm `flip` cfgTypesTringle) listeArmOrd

    ...

    It took me a fair while (I'm talking on the order of half a minute) to
    figure out what that meant

    "Wow, das ist was, was ich nicht gleich verstanden haben, aber auf gar keinen Fall den Verdacht aufkommen lassen, ich würde mich schwer tun, Haskell zu verstehen, bzw. Haskell wäre allgemein unverständlich"

    Ertes Beispiel ist übrigens wieder sowas.

    ertes schrieb:

    eq = (==)

    Natürlich versteht man das auch, die Obfuscation hält sich hier sehr in Grenzen, trotzdem ist eq a b = a == b verständlicher. Warum schreibt man das so kompakt? Doch nicht um am Ende 2 Zeichen zu sparen, oder?


Anmelden zum Antworten