Funktionale Programmierung mit Haskell



  • minhen schrieb:

    Aber Rekursion - und ohne die geht es in deklarativen Sprachen nicht wirklich - das ist eine ganz andere Nuss. Die kann man ihnen fünfmal erklären und sie produzieren dann immer noch *hust* Mist *hust* 😉

    Das Problem an der Sache ist, dass man sagt: "Rekursion ist wenn eine Funktion sich selber aufruft." Das ist so abstrakt, dass der Zuhörer reflexartig sagt: "Verstehe ich nicht." Wenn man ihnen aber ein paar Beispiele präsentiert und wie man sich Schritt für Schritt immer komplizierteren Problemen nähert, so wird das alles plötzlich total natürlich.

    Denke man mal an die ganzen Graphen und Baum-Algorithmen. Ohne Rekursion wäre die meisten nicht so einfach nachvollziehbar.



  • ProgChild schrieb:

    minhen schrieb:

    Aber Rekursion - und ohne die geht es in deklarativen Sprachen nicht wirklich - das ist eine ganz andere Nuss. Die kann man ihnen fünfmal erklären und sie produzieren dann immer noch *hust* Mist *hust* 😉

    Das Problem an der Sache ist, dass man sagt: "Rekursion ist wenn eine Funktion sich selber aufruft." Das ist so abstrakt, dass der Zuhörer reflexartig sagt: "Verstehe ich nicht." Wenn man ihnen aber ein paar Beispiele präsentiert und wie man sich Schritt für Schritt immer komplizierteren Problemen nähert, so wird das alles plötzlich total natürlich.

    Nein, ist es nicht. Oder glaubst du ernsthaft, ich rede von solchen Erklärungen:

    Erklärung 1: Rekursion ist, wenn sich eine Funktion selbst aufruft.
    Versteht ihr nicht? Ok:
    Erklärung 2: Eine sich selbst aufrufende Funktion nennt man rekursiv.
    Versteht ihr nicht? Ok:
    Erklärung 3: Rekursiv bedeutet, dass sich die Funktion immer wieder selbst aufruft.
    Versteht ihr immer noch nicht? Mensch, seid ihr doof!

    Wenn du das unter "Rekursion erklären" verstehst, nur weil man eine andere Meinung als du hast ... dann brauchen wir das Thema gar nicht weiter diskutieren, weil es dann schlicht sinnlos wäre.



  • sollte es nach der neuen Rechtschreibung nicht konsequenterweise 'funkzionale Programmierung' heißen?

    - vgl 'Differenzial' vs 'Differential'





  • u_ser-l schrieb:

    sollte es nach der neuen Rechtschreibung nicht konsequenterweise 'funkzionale Programmierung' heißen?

    - vgl 'Differenzial' vs 'Differential'

    Seit ich letztens in einer Zeitung "neudeutsche Getrenntschreibung bzw. Getrennt Schreibung" gelesen hab, fange ich an, mich für die deutsche Sprache zu schämen ...



  • denkt der Mensch von Natur aus überhaupt in Funktionen und nicht vielmehr in Aktionen?

    Kuchen := backen(verstreichen(rühren(Mehl, Wasser, Butter, Zucker), Backpinsel, Öl, Blech), 180 C)
    

    wahrscheinlich werden nicht umsonst im Mathematikunterrich arithmetische Operation (also Aktionen) bereits in der Grundschule definiert, wogegen Funktionen (und Komposition) erst Jahre später in der Mittelstufe gelehrt werden.



  • u_ser-l schrieb:

    sollte es nach der neuen Rechtschreibung nicht konsequenterweise 'funkzionale Programmierung' heißen?

    😃 👍
    Aber das hätte ja kein Niwo mehr.



  • und eben weil der Mensch von Natur aus eher in Aktionen als in Funktionen denkt, waren Seiteneffekte (auf globale Variablen usw.) stets eine ergiebige Fehlerquelle - beim menschlichen Denken steht von Natur aus eben die Aktion und nicht das E/A-Verhalten im Vordergrund, das muß erlernt oder anerzogen werden, beispielsweise, indem sich der Programmierer durch Vermeidung globaler Variablen vor solchen Fehlern schützt, oder eben durch funktionale Programmierung.



  • @ProgChild: Ich kann dir versichern, dass Microsoft Research eine ganze Reihe von produktiven "Dingen" geschaffen hat. Aber du kannst dich auch selber davon überzeugen indem du dir einfach mal ein paar ihrer Veröffentlichungen anschaust (z.B. "Runtime Support for Multicore Haskell"). Viel wird über die ICFP (international conference on functional programming) oder das JFP (journal on functional programming) veröffentlicht.

    Natürlich ist Haskell standardisiert worden, allerdings ist das 11 Jahre her. Seither wurde an der Sprache aber viel weitergefeilt. Diese Neuerungen sind als Extensions verwendbar, von denen aber viele nur im ghc existieren. Und das liegt auch an Microsoft.

    Und falls du Haskell zu mehr verwenden willst, als dir nur mal anschauen, wie die Sprache so funktioniert, dann kommst du eh nicht am ghc vorbei. Es gibt keinen Haskell-Compiler, der dir deinen Code dermaßen gut optimieren kann (-02). Und ohne Optimierungen kannst du nicht wirklich performante Software in Haskell entwickeln. Auch gibt es sonst keinen Compiler der dir Debugmöglichkeiten bietet (was tatsächlich ein echtes Problem ist).

    @minhen: Ich kann auch nur bestätigen, dass es vielen auf Anhieb nicht leicht fällt, Rekursion tatsächlich zu verstehen. Ob es ein Paradigma gibt, in dem man das am besten/natürlichsten erklären kann, bezweifel ich stark. Das kommt einfach auf den Menschen an.

    Übrigens glaube ich auch nicht, dass funktionale Programmierung den Anspruch hat, eine besonders natürliche Form der Abstraktion zu sein. Möglicherweise ist dies die sequentielle Beschreibung von Algorithmen. Auch Mathematik ist für viele Menschen ein Buch mit sieben Siegeln und doch währe eine Welt ohne Mathe nicht denkbar 🤡.

    Zu guter letzt wollte ich noch sagen, dass ich diese ganze Urzeit-/Jagd-/Evolutions-/Denk-Diskusion für ziemlich sinnfrei halte. Fakt ist doch, dass wir alle nur mutmaßen können, wie das Jagen der Urmenschen stattgefunden hat. Das man aus solchen Mutmaßungen tatsächlich schließen kann, welche Form des Denkens natürlich ist, halte ich für unmöglich.



  • frosch03 schrieb:

    Natürlich ist Haskell standardisiert worden, allerdings ist das 11 Jahre her.

    Nur der Vollständigkeit halber: Der Haskell 98 Report ist zwar von Ende 1998, aber die aktuelle (revidierte) Fassung ist von Dezember 2002, also nur etwas über 6 Jahre alt: http://www.haskell.org/onlinereport/



  • frosch03 schrieb:

    Auch Mathematik ist für viele Menschen ein Buch mit sieben Siegeln und doch währe eine Welt ohne Mathe nicht denkbar 🤡.

    Rechtschreibung auch 🤡

    frosch03 schrieb:

    Zu guter letzt wollte ich noch sagen, dass ich diese ganze Urzeit-/Jagd-/Evolutions-/Denk-Diskusion für ziemlich sinnfrei halte.

    Ganz im Gegenteil. Um menschengerechte Mnemonik entwickeln zu können, muß man menschliches Denken verstehen, und dazu muß man verstehen, wie menschliches Denken zustande kommt und sich entwickelt hat.

    Mnemonik zählt.

    Die Auffassung, der Mensch sei eine Art Roboter mit eingebautem Computer, führt nur zu immer weiteren Syntax-Monstern und unbedienbaren Mensch/Maschine-Interfaces.



  • Das hat doch wenig bis gar nichts mit Mnemonik zu tun. Es ist doch nicht das Problem, dass man sich die Syntax einer Programmiersprache nicht merken könnte. Ich vermute, was Rekursion so schwer macht, ist einfach der Umstand, dass es ein eigenständiges, nicht triviales Konzept ist. Während man bei der prozeduralen Programmierung im Grunde klar der Reihe nach stehen hat, was wann wo wie passiert, ist das bei Rekursion nicht der Fall. Im Gegensatz zu vielen anderen Dingen kann man das, was bei der Rekursion nicht explizit dort steht, auch nicht einfach ignorieren. Bei einem Funktionsaufruf brauch ich mir keinen Kopf um den Stack oder sonstige Interna machen. Und selbst bei der Unifikation zweier Variabeln kann mir das Backtracking erst einmal egal sein. Aber bei der Rekursion ist das, was nicht dort steht, der eigentliche Kern, der springende Punkt, das Thema der ganzen Angelegenheit. Es scheint einfach einfacher zu sein, exakt das hinzutippen, was man sich denkt, wenn man das Problem durchgeht: Erst mach ich das, dann das, dann das. Die zusätzliche Abstraktionsstufe, dass sich der Abflauf hier und dort wiederholt und so und so zusammenfassen lässt und damit diesen eleganten, rekursiven Algorithmus ergibt, die scheint das Problem zu sein. Es ist ja nicht so, dass Anfänger einen gegebenen rekursiven Algorithmus nicht verstehen oder nachvollziehen könnten. Das Problem, das sie meiner Erfahrung nach haben, ist schlicht und ergreifend zu einer Aufgabenstellung selbstständig eine rekursive Lösung zu finden. Das Nachvollziehen einer gegebenen Lösung ist dagegen meistens eher kein Problem.

    Das mit Abstand größte Problem für Anfänger ist aber nachwievor ein Problem einfach nur streng und exakt durchzudenken. Das ist das größte Problem und betrifft sämtliche Programmiersprachen. Bei Rekursion, welche für deklarative Sprachen grundlegend ist, kommt ein zusätzlicher Abstraktionsschritt dazu. Der stellt für sich alleine schon eine Herausforderung dar. Und wenn man als Anfänger noch mit dem Problem Nummer eins hadert, wird's durch Rekursion garantiert nicht besser. Wenn ich für jedes Programm eines Anfängers einen Euro bekommen hätte, bei dem sich die Rekursion in die Unendlichkeit verabschiedet bis in den meisten Fällen der Stack überläuft. Das wär was gewesen 😉

    Aber mit Natürlichkeit und Unnatürlichkeit und wie der Mensch selbst im Hirnkastal denkt, hat das wenig zu tun. Menschen könnten ohne Weiteres "rekursiv denken" und der implizite Abstraktionsschritt im Formalismus würde den Anfängern trotzdem schwer fallen. Das wäre wie mit Sprache und Grammatik. Wir alle haben die deutsche Grammatik intus und können grammatikalische Sätze produzieren, erkennen und verstehen und wissen, wenn ein Satz irgendwie "kein richtiges Deutsch" ist. Und das irgendwie ist der zentrale Punkt. Wehe man muss die Regeln, die man zweifelsohne beherrscht, ausbuchstabieren, aufschreiben oder auch nur bewusst anwenden ...



  • Ohne mich jetzt allzusehr in diesen Thread hineinwerfen zu wollen: Vergesst nicht, dass der persönliche Hintergrund den Zugang zu verschiedensten Konzepten und Sprachen stark beeinflusst.

    Ich habe mal ein paar viertsemestrigen Mathematikern, die vorher noch nie programmiert hatten, die Grundlagen von Haskell gezeigt. Die hatten natürlich keinerlei Schwierigkeiten mit Rekursion (Klar, kommt ja in mathematischen Definitionen auch ständig vor.) und diversen Eigenheiten der funktionalen Programmierung.



  • minhen schrieb:

    Das hat doch wenig bis gar nichts mit Mnemonik zu tun.

    ich finde schon - ein funktionaler Ausdruck wie

    t := a(b(c, x1), x2(d, y(3)), e)
    

    erfordert vom Benutzer, mehr Symbole gleichzeitig im Kurzzeitgedächtnis zu halten als
    der sequentiell notierte

    b_ := b(c,x1)
    y_ := y(3)
    x_ := x2(d,y_)
    res := a(b_,x_,e)
    

    vielleicht nicht das beste Beispiel, aber das Prinzip wird klar.

    Die Kurzzeitgedächtnis-Leistung des Menschen ist eine kostbare Resource, da sie sehr begrenzt ist (nur wenige Bytes), und ein guter Formalismus sollte sparsam damit umgehen - das meine ich auch mit
    "Mnemonik".



  • u_ser-l schrieb:

    der sequentiell notierte

    b_ := b(c,x1)
    y_ := y(3)
    x_ := x2(d,y_)
    res := a(b_,x_,e)
    

    vielleicht nicht das beste Beispiel, aber das Prinzip wird klar.

    -- Haskell
    let b_ = b c x1
        y_ = y 3
        x_ = x2 d y_
    in a b_ x_ e
    


  • ich meine mit "sequentiell" schon, daß die Funktionen y, x, a von einer Art sein, daß sie nur hintereinander ausgeführt werden können sollen, aber zugegeben, das Beispiel ist nicht so gut 🙂



  • Wenn du das meintest, warum schreibst du dann was von der Zahl der Symbole, mit denen das Kurzzeitgedächtnis gleichzeitig hantieren muss? Das sind vollkommen separate Probleme. Das eine löst man durch Einführung von Zwischenvariablen, was in funktionalen Sprachen üblicherweise durch das let-Konstrukt (in Haskell auch nachgestelltes where) geschieht, das andere in Sprachen mit eager evaluation (wie ML oder Scheme) genauso wie in imperativen Sprachen und in Haskell durch Monaden.



  • naja, so ganz unabhängig ist das ja doch nicht. Ähnlich wie in Forth, wo man bei der Programmierung ständig einen Teil des Stacks in Gedanken halten muß. Wie dem auch sei, es ändert aber nichts daran, daß Programme zur Lösung von real-world-Problemen oft gewisse Teilaspekte der real world simulieren müssen, und dabei spielen Zustände und Zustandsübergänge eine wesentliche Rolle, wogegen die reine FP 'zeitlos' ist - da sehe ich einen Ziel-Konflikt.

    Daß FP zur Beschreibung bestimmter Probleme, zB massiv parallelisierbarer Algorithmen und rekursiver Datenstrukturen, gut geeignet ist, bezweifle ich gar nicht. Für jeden Zweck den optimalen Formalismus.



  • u_ser-l schrieb:

    Für jeden Zweck den optimalen Formalismus.

    Das ist sowieso das einzig Sinnvolle.



  • u_ser-l schrieb:

    Ganz im Gegenteil. Um menschengerechte Mnemonik entwickeln zu können, muß man menschliches Denken verstehen, und dazu muß man verstehen, wie menschliches Denken zustande kommt und sich entwickelt hat.

    Kein Plan, wo du jetzt von der Spekulation über das sequentielle/parallel Jagtverhalten von Urmenschen auf Mnemoniks kommst. Und selbst wenn du da irgendwie einen Link herstellen kannst, was hat das mit funProg zu tun???

    u_ser-l schrieb:

    führt nur zu immer weiteren Syntax-Monstern und unbedienbaren Mensch/Maschine-Interfaces.

    Kannst du mir kurz ein funProg-Syntax-Monster nennen, bzw. kurz andeuten was genau du damit meinst?

    Übrigens möchte ich mich davor bewahren, die Leistung meines Kurzzeitgedächtnisses in Bytes auszudrücken :), geschweigedenn darüber zu mutmaßen, wie groß es denn sei. Auch verstehe ich wirklich nicht, was die ganze Thematik überhaupt mit dem Kurzzeitgedächtniss zu tun hat.

    Und dann muss ich dir auch sagen, dass ich die schreibweise deines Beispieles wirklich nicht einfach zu lesen fand. Keine Ahnung wie das den anderen hier ging, aber bei mir hats 'n Moment gedauert :). (Soviel zum Thema, eingänigere Schreibweise :))

    u_ser-l schrieb:

    Programme zur Lösung von real-world-Problemen oft gewisse Teilaspekte der real world simulieren müssen, und dabei spielen Zustände und Zustandsübergänge eine wesentliche Rolle, wogegen die reine FP 'zeitlos' ist - da sehe ich einen Ziel-Konflikt.

    Sowas wie ein Fenstermanager, der sich die Zustände von Fenster merken muss bzw. diese ändert, auf Userinteraktion reagiert, usw.? 🙂


Anmelden zum Antworten