Haskell



  • ertes schrieb:

    CStoll schrieb:

    Hast du schonmal daran gedacht, daß nicht jede Funktion garantieren kann, daß ihr Rückgabewert positiv ist? Einfachstes Beispiel ist die Subtraktion, also wie würdest du die schreiben, um f(x,y)=sqrt(x-y) ohne Laufzeitprüfungen berechnen zu können?

    Deine Funktion f kompiliert einwandfrei. Sie kann nur nicht mit jedem Argumentpaar ausgeführt werden. Wenn der Compiler beweisen kann, dass x - y niemals negativ wird, also dass x ≥ y ist, dann ist auch dein Funktionsaufruf gültig. Falls du das nicht statisch sicherstellen kannst, musst du das eben zur Laufzeit machen. Das lässt sich machen, aber es wird mir langsam zu anstrengend, für alles Codebeispiele zu liefern.

    Ich habe mehrfach gesagt, dass Haskell für diese Art von statischen Garantien nicht geeignet ist. Es wird Zeit, dass du das berücksichtigst. Wenn du solche Garantien willst, musst du Agda oder Coq nehmen.

    Das heißt also, sobald die verwendeten Formeln etwas komplexer werden, muß ich doch wieder manuell prüfen ob die Parameter korrekt sind.

    Der Compiler hat eventuell ein anderes Verständnis von Kontext als du 😉 Und außerdem habe ich gehört, daß es im neuesten C++ Standard das Schlüsselwort auto geben soll, daß diese redundanten Typ-Nennungen reduziert.

    Das ist richtig. Typinferenz in Haskell ist global, und in Standard-H98 musst du normalerweise keine Typensignaturen schreiben. Aber ich sehe es als guten Programmierstil an, sie trotzdem anzugeben, da die Typen deine Spezifikation sind.

    Aber aus den Typen alleine kann man trotzdem nicht alle herleiten - d.h. wenn du in einer komplexeren Formel ein Vorzeichen verwechselt oder eine Klammer falsch gesetzt hast, siehst du trotzdem erst zur Laufzeit, daß das Ergebnis von deinen Erwartungen abweicht. Wie findest du dann heraus, wo der Fehler lag? (in imperativen oder objektorientierten Sprachen würde ich dazu den Debugger nutzen)

    Außerdem: Wenn ich nur die Funktionsdefinition ohne explizite Typangaben schreibe, woher weiß der Compiler dann, welche Bedingungen er an die beteiligten Typen stellen soll?

    Und wo ziehst du die Grenze zwischen nötiger und unnötiger Redundanz?

    Sobald sie sich anfühlt wie Boilerplate ist sie für mich unnötig.

    Und wie fühlt sich "Boilerplate" an? Es mag ja sein, daß ich daran gewöhnt bin, aber mich stört es nicht, daß die explizite Angabe der Template-Parameter in C++ ein wenig länger wird als in Haskell.

    PS: Meine Frage nach der Validierung von Sortieralgorithmen durch den Compiler hast du auch nicht beantwortet.

    Habe ich überlesen, sorry. Sortiertheit ist eigentlich relativ einfach statisch zu garantieren. Das habe ich schon mal gemacht via GADTs.

    Im Werfen mit (unbekannten) Begriffen bist du schon Weltklasse 😃
    Nehmen wir mal an, ich schreibe eine Funktion vom Typ (Ordered a) => [a] -> [a] und behaupte, daß für beliebige Eingaben (die zur Compilezeit unbekannt sind) diese Funktion immer eine aufsteigend sortierte Liste zurückgibt, die die selben Einträge enthält wie die Eingabe. Wie kann ich diese Behauptung durch den Compiler beweisen lassen?

    [quote="knivil"][...]

    Du verwechselst da was. [...]

    Es ist interessant zu sehen, daß jetzt schon erste Meinungsverschiedenheiten innerhalb der Haskell-Fraktion auftreten 😃



  • ertes schrieb:

    CStoll schrieb:

    Hast du schonmal daran gedacht, daß nicht jede Funktion garantieren kann, daß ihr Rückgabewert positiv ist? Einfachstes Beispiel ist die Subtraktion, also wie würdest du die schreiben, um f(x,y)=sqrt(x-y) ohne Laufzeitprüfungen berechnen zu können?

    Deine Funktion f kompiliert einwandfrei. Sie kann nur nicht mit jedem Argumentpaar ausgeführt werden. Wenn der Compiler beweisen kann, dass x - y niemals negativ wird, also dass x ≥ y ist, dann ist auch dein Funktionsaufruf gültig. Falls du das nicht statisch sicherstellen kannst, musst du das eben zur Laufzeit machen.

    Also sind diese Tricks für echtes Programmieren gar nicht geeignet, sondern nur um zum Beispiel sicherzustellen, daß MAIL FROM vor EHLO gesendet wird. Ich muß sagen, daß diese Reihenfolge (oder erst Adresse holen, dann erst Adresse verwenden) für mich nie ein Problem darstellte.



  • die Haskell Version des Glückspiel-Programms ist länger und für Nicht-Haskellaner schwerer zu verstehen

    Das Beispiel wurde ja auch so ausgewaehlt, um genau das zu demonstrieren. Deswegen habe ich mich auch geweigert eine Implementation anzugeben, da dann ueber Haskell an diesem einen Beispiel gerichtet wird.

    Es ist interessant zu sehen, daß jetzt schon erste Meinungsverschiedenheiten innerhalb der Haskell-Fraktion auftreten

    Wenn es zwei Loesungen A und B fuer ein Problem gibt, werden manche A und manche B waehlen.



  • besonders beeindruckend fand ich damals die kurze Def. des QuickSort-Algos:

    qs [] = []
    qs (x:xs) = qs [y|y<-xs; y<=x] ++ [x] ++ qs [y|y<-xs; y>x]
    

    In Smalltalk ist quicksort auch ein Einzeiler, und smalltalk ist eigentlich eine OOP-Sprache:

    Object class compile:'q:a a size<=1 ifTrue:[^a].^(self q:(a allButFirst select:[:i|i<a first])),a first asArray,(self q:(a allButFirst select:[:i|i>=a first]))'.
    
    Beispiel: 
    
    Object q: #(8 4 5 3 2 1 4 7). "#(1 2 3 4 4 5 7 8)"
    

    ertes schrieb:

    Die Semantik von Listen schreit nach einer MergeSort-Implementierung, und die ist tatsächlich sehr effizient. Mit zwei Zeilen Code kommst du dann allerdings nicht mehr aus.

    Im von mir benutzten Smalltalk-System schon: 😃

    #(3 8 1 3 5 4) mergeSortFrom: 1 to: 6 by: [ :x :y | x <= y ]. "#(1 3 3 4 5 8)"
    


  • !rr!rr_. schrieb:

    ertes schrieb:

    Die Semantik von Listen schreit nach einer MergeSort-Implementierung, und die ist tatsächlich sehr effizient. Mit zwei Zeilen Code kommst du dann allerdings nicht mehr aus.

    Im von mir benutzten Smalltalk-System schon: 😃

    #(3 8 1 3 5 4) mergeSortFrom: 1 to: 6 by: [ :x :y | x <= y ]. "#(1 3 3 4 5 8)"
    

    Nee, es ging nicht um den Aufruf, der in eine Zeile paßt, sondern um die Definition.



  • In Smalltalk ist quicksort auch ein Einzeiler, und smalltalk ist eigentlich eine OOP-Sprache:

    Natuerlich kannst du alles in einer Zeile schreiben. Unter dieser Praemisse ist jedes C oder C++ Programm ein Einzeiler. 🙄 Und was das mit OOP zu tun hat, ist auch fraglich.



  • @knivil: Darf ich dich auf eine deiner früheren Aussagen aufmerksam machen?

    knivil schrieb:

    gegen alle Probleme der (Programmierer)Welt ist

    Bitte nenne die Probleme und ich kann dir sagen, wie Haskell im Vergleich zu imperativen Sprachen hilft.

    -> da hat dir jemand ein Beispiel geliefert, um diese Aussage zu bestätigen - und du erklärst einfach, das Beispiel sei unpassend 🙄 so kann man sich auch aus der Affäre ziehen.

    Auf meinen Vorschlag mit dem Telefonbuch bist du auch nicht näher eingegangen. Es muß ja kein komplettes Programm mit grafischer Oberfläche sein, mir würde da schon die grundlegende Programmlogik ausreichen, um folgende Operationen zu unterstützen:

    • insert(name,telefon)
      trägt den Datensatz aus 'name' und 'telefon' in die Datenbasis ein (zusammen mit einer eindeutigen Kennung)
    • update(id,name,telefon)
      ersetzt den Inhalt des Datensatzes mit der Kennung id durch die übergebenen Werte
      (alternativ auch update_name(id,name) und update_tel(id,telefon)
    • delete(id)
      löscht den Datensatz mit der Kennung id
    • find_name(name) und find_tel(telefon)
      liefert eine Liste aller Datensätze, die den angegebenen Namen bzw. Telefonnummer enthalten


  • Nein, ich habe es nicht als unpassend erklaert. Fuer das Telefonbeispiel musst du dich aber eine Woche gedulden (dann habe ich Zeit), wenn du Ein- und Austragen in O(log n) haben willst und die Datenstrukturen rein funktional sein sollen. Hier schnell mal die Datenstruktur Telefonbuch und Eintraege. Test wie das Pruefen, ob ein Eintrag bereits vorhanden ist etc. habe ich jetzt mal weggelassen. Eine eindeutige Id bekommst du durch die StateMonad im Hauptprogramm (main ebenfalls weggelassen). Ich habe auch noch nicht nachgesehen, welche Abstraktion mir Haskellbibliotheken in diesem konkreten Fall anbieten.

    type Name = String
    type TelNumber = String
    type Id = Integer
    type Entry = (Id, Name, TelNumber)
    type TBook = [Entry]
    
    insert :: Entry -> TBook -> TBook
    insert e tb = e:tb
    
    update :: Entry -> TBook -> TBook
    update (i,n,t) = map update'
        where update' (i',n',t') | i == i' = (i,n,t)
                                 | otherwise = (i',n',t')
    
    findName :: Name -> TBook -> TBook
    findName n = filter test
        where test (_,n',_))= n == n'
    
    -- analog fuer findId und findTel
    


  • wie wär's hiermit? 3 Minuten 🙂

    kontakte := { 1 -> #('foo' 1234) . 2 -> #('Meyr' 5678) } asDictionary.
    
    "insert:"
    kontakte at: 3 put: #('bar' 333).
    
    "update:"
    kontakte at: 1 put: #('foo' 4321).
    
    "delete:"
    kontakte removeKey: 2.
    
    "insert:"
    kontakte at: 2 put: #('bla' 444).
    
    "find name or tel:"
    kontakte select: [ :k | k first = 'foo' or: [ k second = 333 ] ].
    
    "1 -> #('foo' 4321)
     3 -> #('bar' 333)"
    


  • !rr!rr_. schrieb:

    die Haskell Version des Glückspiel-Programms ist länger und für Nicht-Haskellaner schwerer zu verstehen als es die C++ Version für Nicht-C++er ist. Außerdem sehe ich in der haskell-Version 4-mal "do" ... nicht gerade das typischste Element funktionaler Programmierung.

    Du solltest dich damit beschäftigen, was do macht, bevor du darüber urteilst. Es hat nichts mit effektvoller oder sequenzierter Programmierung zu tun. Du kannst ein vollständig funktionales, effektloses Programm mit unbestimmter Auswertungsreihenfolge schreiben mit hunderten von do s. Gleichermaßen kannst du das imperativste Programm der Welt schreiben ohne ein einziges do .

    Gut, der Glücksspiel-Algo ist allerdings auch ein "Heimspiel" für klassische imperative Programmierung. Eine ganz andere Problemstellung, die beispielsweise zustandsfreie rekursive Datenstrukturen verlangte, wäre da eine bessere "Reklame" für Funk Prog.

    Trotzdem ist das Beispiel nicht geeignet, meine Skepsis über die Vorteile von Funk Prog bei "real world"-Problemstellungen zu verringern.

    Nun, in C++ hast du die ganzen klassischen Kontrollstrukturen wie while schon vordefiniert. In Haskell müsstest du sie erst selber definieren. Das wären zwar alles Ein- oder Zweizeiler, aber es wäre meiner Meinung nach unschön, das zu tun. Ich habe hingegen (anders als du als Nicht-Haskeller vielleicht annimmst) ein sehr funktionales Schema genommen, und zwar continuation passing style. Man kann das Beispiel sicher noch funktionaler schreiben, aber dann braucht man schon anspruchsvollere Design Patterns. Ein Beispiel dafür, das ich bereits genannt habe, lautet functional reactive programming (FRP). Damit würde man dieses Beispiel nicht mehr als Abfolge von Prozeduren schreiben, sondern stattdessen den Datenfluss definieren.

    Aber es gibt eine Sorte von imperativen Programmen, in denen Haskell glänzt: Serverprogramme. Da können weder C++, noch Ruby, noch andere Sprachen mithalten, die hier genannt wurden. Die einzige Sprache, der ich in diesem Bereich ebenso kurzen, prägnanten und dennoch schnellen und skalierbaren Code zutraue, ist Erlang.

    Eine andere Sorte von Programmen, bei denen Haskell glänzt, und die oft falsch als natürlich imperativ betrachtet werden, sind Webanwendungen. Diese kann man in Haskell sehr elegant und kurz schreiben. Auch hier gibt es wieder nur eine andere Sprache, der ich ähnliche Qualitäten zutraue, und zwar Racket (Nachfolger von PLT Scheme). Leider geht hier keiner von euch darauf ein.

    CStoll schrieb:

    Das heißt also, sobald die verwendeten Formeln etwas komplexer werden, muß ich doch wieder manuell prüfen ob die Parameter korrekt sind.

    So ist es. Haskell garantiert hier nur, dass keine falschen Werte in das System eindringen. Deine Prüfung muss also typenmäßig stimmen, sonst kompiliert sie nicht.

    Aber aus den Typen alleine kann man trotzdem nicht alle herleiten […]

    Doch, kann man. Ich habe dir Referenzen dazu gegeben. Wenn du sie ignorierst, bist du selber schuld.

    Außerdem: Wenn ich nur die Funktionsdefinition ohne explizite Typangaben schreibe, woher weiß der Compiler dann, welche Bedingungen er an die beteiligten Typen stellen soll?

    Er leitet den Typen aus deiner Funktionsdefinition ab. Wenn deine Definition f = (+) lautet, dann muss es sich bei f um eine binäre Funktion mit zwei Argumenten vom gleichen Typ handeln, die beide Instanzen der Klasse Num sind. Selber spezifizieren musst du, wenn du einen spezielleren Typ haben willst, etwa f :: Integer → Integer.

    Mit anderen Worten: Gedanken lesen kann der Compiler nicht. Die Typen sind deine Spezifikation. Wenn du keine Typen angibst, dann leitet der Compiler die Spezifikation her, und die ist evtl. liberaler als die, die du willst.

    Es ist interessant zu sehen, daß jetzt schon erste Meinungsverschiedenheiten innerhalb der Haskell-Fraktion auftreten 😃

    Und jetzt? Als ob sich C++-Programmierer immer einig wären. Deine Aussage hat so viel Inhalt wie eine Tube Vaseline nach einer Pädophilenorgie.

    volkard schrieb:

    Also sind diese Tricks für echtes Programmieren gar nicht geeignet, sondern nur um zum Beispiel sicherzustellen, daß MAIL FROM vor EHLO gesendet wird. Ich muß sagen, daß diese Reihenfolge (oder erst Adresse holen, dann erst Adresse verwenden) für mich nie ein Problem darstellte.

    Ist dir "Beispiel" ein Begriff? Diese "Tricks" kann man für alles anwenden.

    !rr!rr_. schrieb:

    Im von mir benutzten Smalltalk-System schon: 😃

    #(3 8 1 3 5 4) mergeSortFrom: 1 to: 6 by: [ :x :y | x <= y ]. "#(1 3 3 4 5 8)"
    

    In jedem Haskell-System auch:

    > sort [3, 8, 1, 3, 5, 4]
    [1, 3, 3, 4, 5, 8]
    

    Und noch etwas: Mein Haskell-Code ist kürzer als dein Smalltalk-Code. 😉

    CStoll schrieb:

    Auf meinen Vorschlag mit dem Telefonbuch bist du auch nicht näher eingegangen. Es muß ja kein komplettes Programm mit grafischer Oberfläche sein, mir würde da schon die grundlegende Programmlogik ausreichen, um folgende Operationen zu unterstützen: […]

    Bitte schön, hier der Haskell-Code dazu:

    import Data.Map
    

    @!rr!rr_.: Ich war schneller. Und wieder ist mein Code kürzer. 😉



  • ertes schrieb:

    CStoll schrieb:

    Das heißt also, sobald die verwendeten Formeln etwas komplexer werden, muß ich doch wieder manuell prüfen ob die Parameter korrekt sind.

    So ist es. Haskell garantiert hier nur, dass keine falschen Werte in das System eindringen. Deine Prüfung muss also typenmäßig stimmen, sonst kompiliert sie nicht.

    OK, wir haben eine Funktion sqrt(), die nur positive Zahlen als Parameter entgegennimmt, eine Funktion arcsin(), die nur Zahlen im Bereich [-1,1] akzeptiert und einige weitere die auch ihre jeweiligen Einschränkungen haben. Und aus diesen Funktionen wollen wir nun komplexere Funktionen zusammenbauen (z.B. die pq-Formel für quadratische Gleichungen). Allerdings kannst du bei den meisten Funktionen nicht garantieren, daß ihre Werte in einem bestimmten Bereich bleiben, d.h. du mußt die zusammengesetzte Funktion mit Fallunterscheidungen spicken, um die Wertebeschränkungen sicherzustellen.
    [/quote]

    Aber aus den Typen alleine kann man trotzdem nicht alle herleiten […]

    Doch, kann man. Ich habe dir Referenzen dazu gegeben. Wenn du sie ignorierst, bist du selber schuld.

    Du hast einige Begriffe in den Raum geworfen.

    Und eventuell solltest du meine Bemerkungen auch zu Ende lesen. Klar kannst du deine Typen und Funktionen so weit einschränken, daß sie nur auf eine bestimmte Art verwendet werden können, aber was für einen Sinn macht das? Und solange die beteiligten Ausdrücke mit den selben Typen zusammenpassen, wird dein Compiler keinen Unterschied bemerken.

    Bitte schön, hier der Haskell-Code dazu:

    import Data.Map
    

    @!rr!rr_.: Ich war schneller. Und wieder ist mein Code kürzer. 😉

    Und wie sieht der in der Anwendung aus?
    (PS: eine vorgefertigte Library zu verwenden ist keine Kunst - das geht in C++ genauso einfach)



  • CStoll schrieb:

    OK, wir haben eine Funktion sqrt(), die nur positive Zahlen als Parameter entgegennimmt, eine Funktion arcsin(), die nur Zahlen im Bereich [-1,1] akzeptiert und einige weitere die auch ihre jeweiligen Einschränkungen haben. Und aus diesen Funktionen wollen wir nun komplexere Funktionen zusammenbauen (z.B. die pq-Formel für quadratische Gleichungen). Allerdings kannst du bei den meisten Funktionen nicht garantieren, daß ihre Werte in einem bestimmten Bereich bleiben, d.h. du mußt die zusammengesetzte Funktion mit Fallunterscheidungen spicken, um die Wertebeschränkungen sicherzustellen.

    Nein, die Funktionen kannst du zusammensetzen, wie du willst, solange die Typen passen. Es kommt auf die Werte an, die in das System geschickt werden. Aber ist auch egal, denn sowas zu bewerkstelligen ist in Haskell zu aufwendig, um praktikabel sein. Ich sage es jetzt zum letzten mal und werde dann auch nicht weiter auf das Thema eingehen: Haskell ist nicht dafür geeignet, numerische Korrektheit von Formeln zu beweisen. Es ist möglich, aber viel zu aufwendig. Schau dir Agda und Coq an, wenn dich das Thema interessiert. Thema ist meinerseits beendet.

    Du hast einige Begriffe in den Raum geworfen.

    Nun, ich traue den meisten hier zu, eine Suchmaschine richtig zu benutzen. Aber ich habe auch schon Links gepostet. Du wolltest z.B. praktischen, produktiven Code sehen. Ich habe dir welchen verlinkt. Plötzlich gings du überhaupt nicht mehr darauf ein. Du gehst nur auf die Themen ein, in denen du vermutest, dass du mir widersprechen und/oder Haskell in den Boden stampfen kannst. Hat es dich so erschreckt, dass richtige Real World-Bibliotheken in Haskell gibt, und dass man mit denen tatsächlich produktiv arbeiten kann?

    Und eventuell solltest du meine Bemerkungen auch zu Ende lesen. Klar kannst du deine Typen und Funktionen so weit einschränken, daß sie nur auf eine bestimmte Art verwendet werden können, aber was für einen Sinn macht das? Und solange die beteiligten Ausdrücke mit den selben Typen zusammenpassen, wird dein Compiler keinen Unterschied bemerken.

    So ist es. Und wenn du den Sinn darin nicht siehst, dann hat es keinen Wert, darüber zu diskutieren. Du kannst in Haskell viele statische Garantien erreichen, die in C++ undenkbar sind, aber es hat keinen Wert, dir das näherzubringen. Einerseits bist du versteift in deiner Überzeugung, andererseits bist du aber nicht bereit, Haskell erst mal wirklich auszuprobieren, bevor du urteilst.

    Wie schon gesagt: Ich kenne C++ und Haskell, beide aus mehrjähriger Erfahrung. Du kennst nur C++ und zeigst keine Bereitschaft, das zu ändern. Somit ist die ganze Diskussion, die wir führen, Zeitverschwendung.

    Bitte schön, hier der Haskell-Code dazu: […]

    Und wie sieht der in der Anwendung aus?

    Nicht anders als bei entsprechenden C/C++/Ruby/Smalltalk-Bibliotheken, außer dass diese Bibliothek effektfrei ist. Beispiel:

    newHeaders = M.insert "Content-type" "text/plain" oldHeaders
    

    Wenn man seinen Code richtig funktional schreibt, sieht man da aber meistens nur entweder auf der rechten oder auf der linken Seite einen Namen, etwa wenn man mit StateT arbeitet: modify (M.insert "Content-type" "text/plain") .

    (PS: eine vorgefertigte Library zu verwenden ist keine Kunst - das geht in C++ genauso einfach)

    Warum nicht? Machen die anderen doch auch. Außerdem ist Haskell sehr gut mit Datenstrukturen. C++ würde ziemlich alt gegenüber Haskell aussehen, wenn ich anfangen würde, die B-Tree-Struktur selber zu entwickeln. Aber ich denke, ich nehme mir auch so genug Zeit für das Forum hier. 😉



  • ertes schrieb:

    Aber ich denke, ich nehme mir auch so genug Zeit für das Forum hier. 😉

    Sehr gut, kannst du noch etwaszum Thema Webentwicklung mit Haskell oder Racket sagen?



  • Bashar schrieb:

    ertes schrieb:

    Aber ich denke, ich nehme mir auch so genug Zeit für das Forum hier. 😉

    Sehr gut, kannst du noch etwaszum Thema Webentwicklung mit Haskell oder Racket sagen?

    Nunja, ich habe bisher nur gesagt, dass es möglich ist. Ich hoffe, du fragst aus Interesse und nicht aus dem Druck heraus, den Flamewar fortzusetzen.

    Für Haskell gibt es ein paar Web-Frameworks, darunter (alphabetisch) Happstack, Salvia und Yesod. Ich persönlich bevorzuge Yesod, da es mehr Integration bietet und speziell für zügige, sichere Webprogrammierung entwickelt wurde. Es basiert auf dem MVC-Pattern.

    Racket kommt mit einem eigenen Web-Framework, das auf einem ganz eigenen Design-Pattern basiert. Es benutzt das in Scheme fest verdrahtete Konzept der Continuations. Auch eine sehr geniale Idee, die ebenfalls rapide Webentwicklung ermöglicht.

    Was man aber bedenken muss: Die Wege, die Haskell und Racket im Webbereich gehen, unterscheiden sich grundlegend von dem, was man von den gängigen Sprachen gewohnt ist.



  • Sieht aus wie Nischen-Frameworks aus, Schade 😞



  • @!rr!rr_.: Ich war schneller. Und wieder ist mein Code kürzer. 😉

    der Vergleich ist unfair - Smalltalk ist eine OO-Sprache und macht Funktionales wie den qsort-Einzeiler nur im Nebenjob und dabei trotzdem eine sehr gute Figur.

    Für haskell dagegen ist Funktionales der Hauptjob. Kann haskell ebensogut OO wie smalltalk Funktional kann? 🙂



  • ertes schrieb:

    Nunja, ich habe bisher nur gesagt, dass es möglich ist. Ich hoffe, du fragst aus Interesse und nicht aus dem Druck heraus, den Flamewar fortzusetzen.

    Der Flamewar interessiert mich nicht. Ich hab nur schonmal was von diesem Continuation-basierten Ansatz gehört (leider nicht vertieft) und mich gefragt, ob es in Haskell ähnlich gemacht wird oder ob es andere Haskell-spezifische Techniken, die einem dabei helfen können, gibt.

    Für Haskell gibt es ein paar Web-Frameworks, darunter (alphabetisch) Happstack, Salvia und Yesod. Ich persönlich bevorzuge Yesod, da es mehr Integration bietet und speziell für zügige, sichere Webprogrammierung entwickelt wurde. Es basiert auf dem MVC-Pattern.

    Schau ich mir mal an.



  • ertes schrieb:

    Außerdem ist Haskell sehr gut mit Datenstrukturen. C++ würde ziemlich alt gegenüber Haskell aussehen, wenn ich anfangen würde, die B-Tree-Struktur selber zu entwickeln. Aber ich denke, ich nehme mir auch so genug Zeit für das Forum hier. 😉

    Vermutlich wieder ist Haskell deutlich "schneller" aber wenn man dann tatsächlich mal nachmißt, ist es hoffnungslos lahm, aber mit "schneller" war in Wirklichkeit schon die ganze Zeit gemeint, daß man den Code schneller eingetippt hat.



  • Zeus schrieb:

    Sieht aus wie Nischen-Frameworks aus, Schade 😞

    Natürlich sind die Frameworks nicht weit verbreitet, aber deswegen sind sie nicht ungeeignet. Wenn du Interesse hast, einfach mal ausprobieren. Ich wüsste nicht, was etwa in Yesod schwerer/komplizierter zu realisieren sein könnte als in irgendeinem anderen Framework.

    !rr!rr_. schrieb:

    @!rr!rr_.: Ich war schneller. Und wieder ist mein Code kürzer. 😉

    der Vergleich ist unfair - […]

    Ich wollte nur ein Bisschen darauf herumreiten. 😉 Allerdings muss ich ehrlich sagen, aus der Smalltalk-Syntax werde ich nicht schlau, ohne davor irgendein Tutorial gelesen zu haben.

    Bashar schrieb:

    Der Flamewar interessiert mich nicht. Ich hab nur schonmal was von diesem Continuation-basierten Ansatz gehört (leider nicht vertieft) und mich gefragt, ob es in Haskell ähnlich gemacht wird oder ob es andere Haskell-spezifische Techniken, die einem dabei helfen können, gibt.

    Haskell macht es ganz anders und jedes Framework hat sein eigenes Konzept. Yesod etwa benutzt die guten alten Monaden (die Antwort wird nach bestimmten Regeln berechnet), während Happstack mit Monoiden arbeitet (es gibt den Null-Webserver, der immer 404 zurückgibt, und eine Webapplikation ist eine Summe von Webservern). Salvia habe ich mir noch nicht angesehen.

    Das CPS-Konzept von Racket finde ich eigentlich echt genial. Es ist prinzipiell möglich, das auch in Haskell zu bekommen, aber bisher habe ich noch keine praktischen Ansätze gesehen.

    volkard schrieb:

    Vermutlich wieder ist Haskell deutlich "schneller" aber wenn man dann tatsächlich mal nachmißt, ist es hoffnungslos lahm, aber mit "schneller" war in Wirklichkeit schon die ganze Zeit gemeint, daß man den Code schneller eingetippt hat.

    Dumme, zusammenhanglose Behauptung. Bleib sachlich oder halt dich einfach raus.



  • ertes schrieb:

    volkard schrieb:

    Vermutlich wieder ist Haskell deutlich "schneller" aber wenn man dann tatsächlich mal nachmißt, ist es hoffnungslos lahm, aber mit "schneller" war in Wirklichkeit schon die ganze Zeit gemeint, daß man den Code schneller eingetippt hat.

    Dumme, zusammenhanglose Behauptung. Bleib sachlich oder halt dich einfach raus.

    Verzichte doch einfach auf die unpassenden Seitenhiebe gegen C++.
    http://shootout.alioth.debian.org/u64q/benchmark.php?test=binarytrees&lang=all


Anmelden zum Antworten