Haskell



  • 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?



  • Eine direkte Konkurrenz von C++ und Haskell sehe ich aber nicht, die Anwendungsgebiete überschneiden sich nur zum Teil.

    👍
    Sehe ich genauso.

    Womit ich mir bei Haskell noch schwer tue ist State. Es gibt da zwar einige schöne Konzepte, aber es fällt mir deutlich schwieriger damit umzugehen als z.B. in C++. Das liegt natürlich nicht zuletzt an meiner deutlich größeren Erfahrung mit C++ als mit Haskell.

    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:

    Ja, soetwas finde ich absolut Schwachsinnig und habe ich so auch noch nicht in echtem Code gesehen. Ich würde das ähnlich wie du schreiben, nur mit kürzeren Namen:

    mf p f xs = filter p (map f xs)
    

    Und das nichtmal um Platz zu sparen, sondern weil ich es gewohnt bin, dass ein Predicate p heißt oder eine Liste mit xs abgeküzrt wird.

    trotzdem ist eq a b = a == b verständlicher. Warum schreibt man das so kompakt?

    Ist doch geschmackssache. Subjektiv gefällt mir eq = (==) auch besser, weil ich dann unmittelbar sehe, dass eq das gleiche macht wie (==). Bei der etwas expliziteren Version eq a b = a == b muss man etwas mehr nachdenken.



  • jungerjünger schrieb:

    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.

    Sorry, ich weiß nicht, was du meinst. Also f x x = … ist ein Syntaxfehler.

    CStoll schrieb:

    ertes schrieb:

    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)

    Du hast immer noch das Typensystem, das dir zur Seite steht (am Anfang wohl eher im Weg, bis du lernst, damit umzugehen). Im Low-Level-Bereich wird dir Haskell allerdings nicht verbieten, einen Null-Pointer zu dereferenzieren. Andererseits kommt es wiederum normalerweise nicht vor, dass du Null-Pointer überhaupt bekommst. Nehmen wir als blödes Beispiel an, du willst eine verkettete Liste im klassischen Sinne: Es gibt also eine Variable und einen Zeiger zum nächsten Glied. In C++ hätte das letzte Glied hier einen Null-Pointer. In Haskell würdest du eher Maybe (Ptr a) benutzen und somit kommt ein Null-Pointer gar nicht vor. Der Versuch, vom letzten Glied ins nächste zu springen endet in einem Typfehler zur Kompilierzeit.

    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.

    So ist es. Allerdings sind viele andere Optimierungen möglich. Beispiel: Du suchst die kleinste gerade quadratische natürliche Zahl (x² mit x ∈ ℕ), die größer als 110 ist, und nehmen wir an, es gäbe keine simple Formel dafür: Du erstellst erst eine unendliche Liste von 0 beginnend aufwärts, quadrierst alle Elemente, filterst die Ergebnisliste, sodass nur gerade Zahlen übrigbleiben, dann verwirfst du so lange den Anfang der Liste, bis das erste Element größer als 110 ist. Dieses Element ist das Ergebnis. Der Code dazu:

    head . dropWhile (<= 110) . filter even . map (^2) $ [0..]

    Durch äquivalente Umformungen wird die Liste vollständig wegoptimiert und es bleibt dieselbe Schleife übrig, die du in C++ von vornherein geschrieben hättest. Das heißt, die referentielle Transparenz wird ein C++-Programm nicht schneller machen, aber sie ermöglicht dir, neue, elegante Design-Patterns zu nutzen, ohne Performance dafür aufzugeben.

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

    Wie sehr mich das wundert, dass dir keine einfallen. Daran haben sich schon andere Leute die Zähne ausgebissen. Wobei – ein solches Problem fällt mir ein, sogar mit Praxisrelevanz: Schreibe ein Agda-Programm, für das unentscheidbar ist, ob es terminiert. 😉

    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)

    Jetzt kommen wir der Sache näher. Du hast bisher noch keine einzige informierte Aussage über Haskell gemacht. Du kannst doch gar nicht beurteilen, wo welche Sprache besser ist.

    OK, die drei Punkte aus deiner letzten Auflistung:
    - typsicher: kann C++ auch

    Nicht in dem Ausmaß.

    - wenn es kompiliert, funktioniert es auch: halte ich immr noch für fragwürdig

    Dazu gibt es sogar einen Wiki-Eintrag.

    - 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

    Und was ist der Hammer? Etwa PHP? Python? Ruby? Das kannst du doch gar nicht einschätzen, wie du selber indirekt zugegeben hast. Tu doch nicht so, als würdest du alle Web-Frameworks der Welt kennen, denn mindestens eines davon kennst du nicht: Yesod.

    - vergleichbar in der Performance: ist für mich kein Kriterium, egal für welche Seite

    Bis zu einem gewissen Grad hast du hier Recht. Allerdings muss man auch sehen, dass Haskell eine wesentlich höhere Abstraktionsebene besitzt als die meisten anderen Sprachen. Es hat lange gedauert, bis sich das mit so guter Performance kombinieren ließ. In GHC steckt unglaublich viel Erfahrung. Das heißt: Du kannst höhere Abstraktionsgrade nutzen, ohne dafür Performance aufgeben zu müssen. Ich habe oben ein konkretes Beispiel dazu genannt. Wenn du in Haskell C++ programmierst, hast du keinen Vorteil, und wahrscheinlich eher noch einen Nachteil.

    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.

    Hab ich doch schon. Resultat war der Vorwurf, ich sei ein Dummschwätzer, der nur mit Fachbegriffen um sich wirft.

    volkard schrieb:

    ertes schrieb:

    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.

    "Statisch" und "zur Laufzeit(!)" vertragen sich nicht besonders gut, findest du nicht?

    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 bin bisher auf jedes Argument tief eingegangen. Es gibt aber Argumente von mir, auf die gar nicht eingegangen wurde, bzw. auf die CStoll als einziger erst jetzt ansatzweise eingeht. Du machst es dir nur ziemlich einfach mit deiner Behauptung. "Es ist zwecklos, mit dir zu diskutieren", ist eine billige Ausrede.

    ipsec schrieb:

    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?

    Ich nicht. Du hast völlig Recht: Das ist übertriebene Abstrahierung. Ich persönlich hätte aber keine der beiden Varianten gewählt, sondern diese:

    mf :: (a -> Bool) -> (b -> a) -> [b] -> [a]
    mf criteria operator = filter criteria . map operator
    

    Zwei Unterschiede: Ich habe eine Typensignatur drin, und durch die allein ist eigentlich völlig klar, was die Funktion tut. Der zweite Unterschied ist: Ich habe nur den letzten Parameter wegabstrahiert. So sieht man relativ deutlich den Datenfluss. Das ist eigentlich Sinn und Zweck der Pointfree-Schreibweise: den Datenfluss expliziter darstellen.

    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.

    So ist es. Interessanterweise kommen solche Codes hauptsächlich von Leuten, die Haskell nicht produktiv einsetzen, sondern nur zum Spaß Code-Schnippsel zusammenbasteln.

    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?

    Das ist Haskell-Grundwissen. Diese Definitionen solltest du nach dem Einstieg im Blindflug lesen können. Für einen Haskell-Programmierer gibt es keinen Unterschied zwischen Funktion und Operator, daher liest sich (==) genauso wie jeder andere Name auch. Ich lese das wie Irgendwer: "eq und (==) sind identisch." Das hat mit Sparen nichts zu tun. Es macht eben direkt die Aussage, die deine Version nur indirekt macht. Du schreibst viele Haskell-Funktionen in dieser Art:

    putStrLn :: String -> IO ()
    putStrLn = hPutStrLn stdout
    


  • ertes schrieb:

    CStoll schrieb:

    ertes schrieb:

    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)

    Du hast immer noch das Typensystem, das dir zur Seite steht (am Anfang wohl eher im Weg, bis du lernst, damit umzugehen). Im Low-Level-Bereich wird dir Haskell allerdings nicht verbieten, einen Null-Pointer zu dereferenzieren. Andererseits kommt es wiederum normalerweise nicht vor, dass du Null-Pointer überhaupt bekommst. Nehmen wir als blödes Beispiel an, du willst eine verkettete Liste im klassischen Sinne: Es gibt also eine Variable und einen Zeiger zum nächsten Glied. In C++ hätte das letzte Glied hier einen Null-Pointer. In Haskell würdest du eher Maybe (Ptr a) benutzen und somit kommt ein Null-Pointer gar nicht vor. Der Versuch, vom letzten Glied ins nächste zu springen endet in einem Typfehler zur Kompilierzeit.

    Und jetzt erkläre mir nochmal, wie man zur Kompilierzeit eine Situation verhindenr will, die erst zur Laufzeit (wenn ich tatsächlich eine konkrete Liste in der Hand halte und durch ihre Elemente iteriere) auftreten kann.
    (und komme mir bitte nicht mit "dafür ist Haskell nicht gedacht").

    So ist es. Allerdings sind viele andere Optimierungen möglich. Beispiel: Du suchst die kleinste gerade quadratische natürliche Zahl (x² mit x ∈ ℕ), die größer als 110 ist, und nehmen wir an, es gäbe keine simple Formel dafür: Du erstellst erst eine unendliche Liste von 0 beginnend aufwärts, quadrierst alle Elemente, filterst die Ergebnisliste, sodass nur gerade Zahlen übrigbleiben, dann verwirfst du so lange den Anfang der Liste, bis das erste Element größer als 110 ist. Dieses Element ist das Ergebnis. Der Code dazu:

    head . dropWhile (<= 110) . filter even . map (^2) $ [0..]

    Durch äquivalente Umformungen wird die Liste vollständig wegoptimiert und es bleibt dieselbe Schleife übrig, die du in C++ von vornherein geschrieben hättest. Das heißt, die referentielle Transparenz wird ein C++-Programm nicht schneller machen, aber sie ermöglicht dir, neue, elegante Design-Patterns zu nutzen, ohne Performance dafür aufzugeben.

    Also quasi von hinten durch die Brust ins Auge.

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

    Wie sehr mich das wundert, dass dir keine einfallen. Daran haben sich schon andere Leute die Zähne ausgebissen. Wobei – ein solches Problem fällt mir ein, sogar mit Praxisrelevanz: Schreibe ein Agda-Programm, für das unentscheidbar ist, ob es terminiert. 😉

    Du hast doch selber erklärt, daß Agda nicht mächtig genug ist, um solche unentscheidbaren Programme zu schreiben, also verzichte ich mal darauf.
    (btw, der Grund warum mir kein Problem einfällt ist wohl, daß mein Studium schon eine Weile her ist - und in der Praxis habe ich mit ganz anderen Aufgaben zu tun als mich um berechenbarkeitstheoretische Fragen zu kümmern)

    - wenn es kompiliert, funktioniert es auch: halte ich immr noch für fragwürdig

    Dazu gibt es sogar einen Wiki-Eintrag.

    Selbst der Beitrag sagt nicht aus, daß du mit Haskell alle Fehler zur Compilezeit verhindern kannst.

    - 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

    Und was ist der Hammer? Etwa PHP? Python? Ruby? Das kannst du doch gar nicht einschätzen, wie du selber indirekt zugegeben hast. Tu doch nicht so, als würdest du alle Web-Frameworks der Welt kennen, denn mindestens eines davon kennst du nicht: Yesod.

    Ich bin kein Web-Entwickler (jedenfalls nicht hauptsächlich, aber ich weiß selber, daß meine Werkzeuge nicht die besten dafür sind), deshalb kann ich dazu nichts sagen.

    Ich nicht. Du hast völlig Recht: Das ist übertriebene Abstrahierung. Ich persönlich hätte aber keine der beiden Varianten gewählt, sondern diese:

    mf :: (a -> Bool) -> (b -> a) -> [b] -> [a]
    mf criteria operator = filter criteria . map operator
    

    Zwei Unterschiede: Ich habe eine Typensignatur drin, und durch die allein ist eigentlich völlig klar, was die Funktion tut. Der zweite Unterschied ist: Ich habe nur den letzten Parameter wegabstrahiert. So sieht man relativ deutlich den Datenfluss. Das ist eigentlich Sinn und Zweck der Pointfree-Schreibweise: den Datenfluss expliziter darstellen.

    Die Signatur gibt zumindest einen Ansatzpunkt, was deine Funktion machen soll, aber da bleiben immer noch zu viele Freiheiten, die damit nicht beantwortet werden. Kommen die Ergebnisse in der selben Reihenfolge vor, die die ursprüngliche Liste vorgegeben hat? Auf welche Weise wird das Filter-Kriterium angewendet (bedeutet true jetzt "übernimm das Argument in die Ergebnisliste" oder "verwirf das Argument")? Für diese Fragen benötigt man doch wieder die genaue Definition.

    Analog können wir als Beispiel diese Signatur verwenden:
    [code}f :: Ordered a => [a] -> [a][/code]
    Kannst du mir ohne die Definition sagen, was beim Aufruf f [5 7 11 3 29] herauskommen wird?



  • Und jetzt erkläre mir nochmal, wie man zur Kompilierzeit eine Situation verhindenr will, die erst zur Laufzeit (wenn ich tatsächlich eine konkrete Liste in der Hand halte und durch ihre Elemente iteriere) auftreten kann.
    (und komme mir bitte nicht mit "dafür ist Haskell nicht gedacht").

    Kurz zum Maybe (Ptr a) (aus meiner Sicht).

    Maybe ist folgendermaßen definiert:
    data Maybe a = Just a | Nothing

    D.h. Maybe (Ptr a) ist entweder Just (Ptr a) oder Nothing , d.h. falls eine C-Funktion einen ungültigen Pointer zurückgibt ( Ptr a ist teil des Foreign Function Interface) wird in Haskell daraus Nothing . Jetzt könntest du eine Funktion f schreiben, die folgendermaßen aussieht:

    f :: Maybe (Ptr a) -> a 
    f Just (Ptr a) = -- Version für einen gütligen Zeiger
    f Nothing = -- Version für einen ungültigen Zeiger
    

    Du kannst also gar nicht mit ungültigen Zeigern hantieren.

    Das könnte man auch in C++ mit Klassen und Überladung irgendwie erreichen, das macht aber niemand, weil das unnötig ineffizient ist. Stattdessen macht man eben manuelles Pattern-Matching. Mir gefällt die Haskell-Version allerdings besser.

    Selbst der Beitrag sagt nicht aus, daß du mit Haskell alle Fehler zur Compilezeit verhindern kannst.

    Du verlangst von Haskell, dass es alle Fehler zur Compilezeit verhindert? Bleib realistisch.
    Es verhindert einige (siehe Maybe (Ptr a) ), aber wie soll es denn alle verhindern?



  • was gibt eigentlich Haskell aus, wenn du den Definitionsbereich einer partiell definierten Funktion verlässt? (d.h. wenn ich für den "Nothing"-Teil nichts sinnvolles machen kann und den Teil offen lasse)

    Irgendwer schrieb:

    Selbst der Beitrag sagt nicht aus, daß du mit Haskell alle Fehler zur Compilezeit verhindern kannst.

    Du verlangst von Haskell, dass es alle Fehler zur Compilezeit verhindert? Bleib realistisch.
    Es verhindert einige (siehe Maybe (Ptr a) ), aber wie soll es denn alle verhindern?

    Ich verlange von Haskell gar nichts. Aber von den Haskell-Vertretern kam die Aussage, daß compilierte Programme fehlerfrei sind. In dem Artikel wurde gezeigt, wie man durch eine Umstellung der Semantik einige Fehler vermeiden kann - aber deswegen kann man trotzdem immer noch genug Mist bauen.



  • was gibt eigentlich Haskell aus, wenn du den Definitionsbereich einer partiell definierten Funktion verlässt? (d.h. wenn ich für den "Nothing"-Teil nichts sinnvolles machen kann und den Teil offen lasse)

    Entweder gibt's einen Pattern-Matching Fehler, d.h. du hast den Nothing Teil komplett weggelassen, oder du wirfst eine Exception oder benutzt error - genauso wie du es in C++ auch machen wirst. Ganz schön kann auch die Maybe-Monade sein, bei der nur weitergemacht wird, solange eine Funktion Just a zurückgibt, ansonsten wird direkt abgebrochen - und das alles ohne ein direktes "if" zu schreiben, da sich das alles im Bind-Operator >>= abspielt.

    Du kannst auch am immer gegen ein beliebiges Pattern matchen:

    data Bar = Foo | Bar | Baz
    f :: Bar -> Int
    f Foo = 1
    f Bar = 2
    f _   = error "Invalid value"
    

    Aber natürlich werden partiell definierte Funktionen vermieden wo es nur geht.

    Aber von den Haskell-Vertretern kam die Aussage, daß compilierte Programme fehlerfrei sind.

    Ja, mit der Aussage hat ertes wohl die Gemüter hier ziemlich in Wallungen gebracht. Ich bin kein erfahrener Haskell-Programmierer, habe aber von erfahrenen Haskellern schon häufig die Aussage gehört und gelesen, dass Programme häufig beim ersten kompilieren laufen.

    Aber vielleicht sind das auch einfach alles schlechte imperative Programmierer und Lüger noch obendrauf. 😉


Anmelden zum Antworten