Haskell



  • das ganze geht mit einer reinen OOP-Sprache a la Smalltalk auch in 2 Zeilen:

    weights := particles collect: [ :i | (oldP value: i) / (newP value: i) ].
    weightsNormed := weights collect: [ :x | x / weights sum ].
    

    - dafür brauche ich also kein Haskell.



  • Die Argumentation über kurze, knappe Formulierung ist einfach nicht zielführend.



  • sogar in 1 Zeile:

    weightsNormed := (particles collect: [ :i | (oldP value: i) / (newP value: i) ]) collect: [ :x | x / weights sum ].
    


  • var weights = from i in particles select oldP(i) / newP(i);
    var sum = weights.Sum();
    var weightsNormed = from i in weights select weights / sum;
    

    Hätte man auch genauso wie die Smalltalk-Version schreiben können:

    var weights = particles.Select(i => oldP(i) / newP(i));
    var weightsNormed = weights.Select(i => i / weights.Sum());
    

    aber dann würde weights.Sum() für jedes Element neuberechnet werden. Ich vermute, das ist in Smalltalk nicht anders.

    Die Einzeiler-Lösung in Smalltalk ist offensichtlich Quatsch, von welchen weights soll denn da die Summe bestimmt werden?

    Insgesamt finde ich die Haskell-Lösung am elegantesten, wegen ihrer Modularität.



  • rüdiger schrieb:

    Das ganze könnte man schon kürzer machen (ungetestet)

    Lustig, dass du dabei stark auf higher-order functions setzt, die aus funktionalen Programmiersprachen kommen.

    !rr!rr_. schrieb:

    Eine Programmiersprache, die I/O nur mit raffinierten Tricks aus der Kategorientheorie hinkriegt und mithilfe von Donuts veranschaulicht, ist nicht einfach, sondern unpraktikabel.

    Mal wieder absoluter Schwachsinn von dir...
    Inzwischen ist für mich der Haskell-Weg, nämlich jegliche Kommunikation mit der Außenwelt explizit zu machen, der schönere. Man sieht schon an der Funktionssignatur, ob IO stattfindet oder nicht. Ich muss dann nicht über Seiteneffekte nachdenken und kann sicher sein, dass ich immer das gleiche Resultat bekomme.



  • Bashar schrieb:

    von welchen weights soll denn da die Summe bestimmt werden?

    weights ist eine Abkürzung für den Ausdruck "particles collect: ...", die ich
    hier einsetzen mußte, weil mir die Zeile sonst zu lang wurde.

    Aber wenn du unbedingt willst ...

    weightsNormed := (particles collect: [ :i | (oldP value: i) / (newP value: i) ]) collect: [ :x | x / (particles collect: [ :i | (oldP value: i) / (newP value: i) ]) sum ].
    


  • funktional und 50% weniger Zeilen als die haskell-Version 🙂



  • Das ist also dein Verständnis von Eleganz? Ich hoffe mal, dass dein Smalltalk-Compiler superduperintelligent ist.



  • funktional und 50% weniger Zeilen als die haskell-Version 🙂

    xD
    Also du meinst bei der Haskell-Version hätte man normalize w = map (/ (sum w)) w nicht auch noch direkt einsetzen können?
    Mach dich nicht lächerlich. 🤡

    Es geht übrigens nicht primär um Kürze, sonder um Abstraktion und Eleganz. Haskell bietet sehr mächtige Abstraktionsmechanismen, vor allem aber komplett andere als C++ (das ist überhaupt nicht abwertend gemeint, ich mag C++ sehr).



  • Irgendwer schrieb:

    Lustig, dass du dabei stark auf higher-order functions setzt, die aus funktionalen Programmiersprachen kommen.

    Funktionszeiger gibt's schon ziemlich lange, man hat halt nur nie einen so griffigen Namen vergeben.

    Die Haskell-Version von otze ist wirklich schön, gefällt mir. Auch das Zusammenspiel von Duck Typing und statischer Typisierung in Haskell 👍



  • Mal nachgehakt schrieb:

    Irgendwer schrieb:

    Lustig, dass du dabei stark auf higher-order functions setzt, die aus funktionalen Programmiersprachen kommen.

    Funktionszeiger gibt's schon ziemlich lange, man hat halt nur nie einen so griffigen Namen vergeben.

    Funktionszeiger sind nicht ausreichend. Man braucht Closures, d.h. implementationstechnisch ein Tupel aus dem Funktionszeiger und allen "eingefangenen" Variablen.
    Der "griffige" Name higher order function dürfte übrigens deutlich älter sein als der Begriff des Funktionszeigers, den dürften schon Church&Co. in den 30ern benutzt haben.

    Die Haskell-Version von otze ist wirklich schön, gefällt mir. Auch das Zusammenspiel von Duck Typing und statischer Typisierung in Haskell 👍

    Haskell hat kein Duck Typing.



  • Bashar schrieb:

    Funktionszeiger sind nicht ausreichend. Man braucht Closures, d.h. implementationstechnisch ein Tupel aus dem Funktionszeiger und allen "eingefangenen" Variablen.

    Och jo, aber so einen weiten Schritt finde ich das nicht. In C++ darf man ja an Templatefunktionen leider keine lokal definierten Typen übergeben, sonst könnte man das auch schon 'ne Weile.
    Versteh mich nicht falsch, Higher Order Functions sind schon eine großartige Sache, aber ihr Aufkommen in den imperativen Sprachen hat imo nichts mit der Existenz der funktionalen zu tun. Genauso, wie ich den Schritt von C nach C++ logisch und wenig innovativ (wenn auch natürlich bedeutend) finde.

    Bashar schrieb:

    Der "griffige" Name higher order function dürfte übrigens deutlich älter sein als der Begriff des Funktionszeigers, den dürften schon Church&Co. in den 30ern benutzt haben.

    Oha, ok.

    Bashar schrieb:

    Haskell hat kein Duck Typing.

    Ich weiß, mein Fehler, ich meinte eigentlich die Dynamik in der Typisierung. Wenn ich da nix falsch verstanden hab, entspräche der Haskell-Code

    sum x y = x + y
    

    ja in C++0x

    template<typename T, typename U>
    auto sum( const T& t, const U& u ) -> decltype(t+u) {
        return t + u;
    }
    


  • Mal nachgehakt schrieb:

    Bashar schrieb:

    Haskell hat kein Duck Typing.

    Ich weiß, mein Fehler, ich meinte eigentlich die Dynamik in der Typisierung. Wenn ich da nix falsch verstanden hab, entspräche der Haskell-Code

    sum x y = x + y
    

    ja in C++0x

    template<typename T, typename U>
    auto sum( const T& t, const U& u ) -> decltype(t+u) {
        return t + u;
    }
    

    Nicht ganz. Templates (ohne Concepts) sind ja eigentlich statisches Duck Typing. Du setzt hier implizit voraus, dass es einen Operator + für t und u gibt. Wenn es den gibt, dann wird er benutzt. Oder, um die Parallele zum Duck Typing noch deutlicher zu machen: Der Code lässt sich genau dann compilieren, wenn t+u mit den konkreten Typen in jeder Instanz einen sinnvollen Ausdruck ergibt.
    In Haskell ist + eine Funktion mit einer bestimmten Signatur. Die ist zwar polymorph und damit für viele Typen anwendbar, aber sie erfordert, dass beide Operanden den gleichen Typ haben und dass dieser Typ eine Instanz der Typklasse Num (IIRC) ist. Dann legt sie noch fest, dass das Ergebnis auch wieder diesen Typ hat. Man kann nicht einfach irgendein + definieren und bei sum unterschieben, es muss immer über eine Instanz von Num geschehen.



  • aber ihr Aufkommen in den imperativen Sprachen hat imo nichts mit der Existenz der funktionalen zu tun.

    Genauso ist es Zufall, dass die funktionalen Sprachen anonyme Funktionen (lambdas) zuerst hatten und diese jetzt in so gut wie jeder imperativen Sprache Einzug finden?



  • higher-order functions, funktionale Programmierung und lambda hat Smalltalk auch. Da wird nur nicht so ein Theater drum gemacht, das sind da einfach Spezialfälle von Blocks:

    [ :o :x :y | o machWasMit: x undMit: y ]
    

    - und Blocks wiederum sind Objekte der Klasse BlockClosure. Bleiben wir also bei OOP 🙂



  • Als ob das ein Argument wäre. Die Haskelleute behaupte auch, dass sie perfektes OOP in Haskell machen können. Und nu?



  • Das kann man nicht vergleichen. Das Block-Konzept in Smalltalk ist ja nicht ein objektorientiertes, mit dem man funktionale Programmierung simuliert. Das *ist* funktional.



  • Lasst den Kreuzzug beginnen! - Männer an die Waffen! - Vollstreck die Ungläubigen mit aller Macht! 😃



  • Lieber Seitenbesucher, schrieb:

    Mich keiner. Den freakC++ wahrscheinlich sein Lehrer/Prof.

    Nö! In der Schule läuft gerade nichts, weshalb ich mich zu einem Vorsemster an der Goethe Uni Frankfurt eingeschrieben. Dort lerne ich das. Ich finds interessant. Nach dem Vorsemester habe ich damit nichts mehr am Hut 😉

    Wir hatten heute eine rekursive Funktion ohne Abbruchbedingung und ich hatte plötzlich "Stack overflow" im Kopf. Mich hat es schon sehr gewundert, dass das Haskell wenig krazt. Das Programm terminiert zwar nicht, aber es stürzt auch nicht ab! Das kann C++ nicht.



  • Muss ja nicht 1:1 so in Maschinencode umgesetzt werden wie man es hinschreibt. Ich glaube du hängst noch zu sehr am Konzept Programmiersprache als etwas absolut Einordbares. Viel eher gilt es aber die richtige Sprache, zum richtigen Zeitpunkt, für den richtigen Zweck zu wählen.

    Es herrscht inzwischen doch ein gewisser Konsens (und das sieht man auch an dem erhöhten Aufkommen der eigenen Techniken in der jeweils anderen Ecke), dass Konzepte von funktionalen als auch imperativen Sprachen nötig sind - wiederum, je nach Einsatzzweck (inwiefern hier überhaupt funktional mit objektorientiert verglichen wird ist nicht zu verstehen, können doch auch funktionale Sprachen objektorientiert sein, oder?).

    MfG SideWinder


Anmelden zum Antworten