19 Punkte von GN⁺ 2024-09-13 | 3 Kommentare | Auf WhatsApp teilen
  • „Unpraktisch“, „akademisch“, „nischig“

    • Das sind die Reaktionen, die Menschen zeigen, wenn sie erfahren, dass Haskell meine Lieblingsprogrammiersprache ist
    • Ich nutze es nicht nur für Hobbyprojekte, sondern auch zum Aufbau echter Webserver
    • Bei Converge leite ich Teams, die mit Haskell arbeiten
  • Missverständnisse über Haskell

    • Probleme, die sich mit einer universellen Programmiersprache lösen lassen, können auch in anderen Sprachen gelöst werden
    • Viele Funktionen, die in Python, Rust, Typescript usw. eingeführt werden, wurden von Haskell inspiriert oder sind dort robuster umgesetzt
    • Es wirkt wie eine Abwandlung der Ideologie „Choose boring technology“
    • Es gibt die falsche Vorstellung, Programmierung sei keine Mathematik und mathematische Elemente müssten ausgeschlossen werden
  • Ziel dieses Artikels

    • Es soll logisch erklärt werden, warum Haskell für die meisten Programmierer die beste Wahl ist
    • Besonders nützlich ist es für Menschen, die produktiv robuste Software schreiben möchten
    • Auch die unterhaltsamen Seiten des Software-Schreibens werden hervorgehoben
  • Verlernen und neu lernen

    • Die meisten Programmierer sind an das imperative Paradigma gewöhnt
    • Haskell ist eine rein funktionale Sprache mit einer steilen Lernkurve
    • Die Sprache Haskell selbst ist leicht zu lernen, wenn man sich auf eine einfache Teilmenge beschränkt
    • Funktionale Programmierung verlangt einen vollständigen Wandel darin, wie Programme aufgebaut werden
    • Dieser Prozess hilft dabei, als Programmierer zu wachsen
    • Zitat von Alan Perlis:

      Eine Sprache, die Ihre Denkweise über Programmierung nicht beeinflusst, ist es nicht wert, gelernt zu werden.

Kurze Erklärung zur Syntax

  • :: kennzeichnet eine Typ-Signatur (z. B. myThing :: String)

  • Funktionsaufrufe verwenden keine Klammern; die Argumente werden nach dem Funktionsnamen durch Leerzeichen getrennt aufgeführt (z. B. doSomething withThis withThat)

  • In Typ-Signaturen sind Kleinbuchstaben Typvariablen und stehen für beliebige Typen (z. B. head :: [a] -> a)

  • Es gibt zwei Arten von Pfeilen, -> und =>:

    • -> beschreibt den Typ einer Funktion (z. B. add1 :: Int -> Int)
    • => beschreibt Einschränkungen für Typvariablen und steht immer zuerst (z. B. add1 :: Num a => a -> a)
  • Kommentare beginnen mit --

  • return ist eine normale Funktion und bedeutet nicht das, was man erwartet

  • do ist syntaktischer Zucker, damit es imperativ aussieht

  • Es gibt mehrere Möglichkeiten, lokalen Variablen Werte zuzuweisen:

    let x = <something> in  
    <expression>  
    

    oder x <- <something>

  • Weniger Fehler machen

    • In vielen Sprachen schreibt man viele Testfälle, damit Code „korrekt“ wird
    • Haskell reduziert diese Last stark durch sein Typsystem und die reine funktionale Programmierung
    • Haskells mächtiges Typsystem liefert konkrete Garantien über Programme und setzt sie strikt durch
    • Merkmale des Typsystems:
      • Keine nullable Typen
      • Fehlbare Berechnungen können ausgedrückt werden
      • Pattern Matching und Vollständigkeitsprüfung
      • Primitive Obsession lässt sich kostenlos vermeiden
  • Vorteile fehlender Nullwerte

    • Da kein null-Wert existiert, weiß man immer, ob ein Wert den erwarteten Typ hat
    • Das verhindert Laufzeitfehler und verkleinert die Fehleroberfläche
  • Darstellung fehlbarer Berechnungen

    • Mit den Typen Maybe und Either lassen sich Berechnungen, die fehlschlagen können, explizit ausdrücken
    • Maybe steht für Berechnungen, die ein Ergebnis haben können oder auch nicht
      safeHead :: [a] -> Maybe a  
      
    • Either kann zwei Arten von Werten haben (Left a oder Right b)
      validateAddress :: String -> Either AddressParseError ValidAddress  
      
  • Pattern Matching und Vollständigkeitsprüfung

    • Alle Eingabedomänen müssen behandelt werden; andernfalls meldet der Compiler einen Fehler
    • Das verhindert Laufzeitfehler und erhöht die Zuverlässigkeit des Programms
  • Vermeidung von Primitive Obsession

    • Mit newtype lassen sich leicht semantisch aussagekräftigere Typen erzeugen
    newtype VenueName = VenueName String  
    newtype EventName = EventName String  
    
  • Vorteile reiner funktionaler Programmierung

    • Daten sind unveränderlich, sodass man sich nicht um Zustandsmutationen kümmern muss
    • Nebeneffekte werden explizit behandelt, und Funktionen hängen ohne Nebeneffekte nur von ihren Eingaben ab
    • Das erhöht Vorhersagbarkeit und Stabilität von Programmen
  • Explizite Behandlung von Nebeneffekten

    • Mit der IO-Monade werden Nebeneffekte im Code getrennt und kontrolliert
    • An der Typ-Signatur einer Funktion erkennt man, dass sie Nebeneffekte auslöst
    sendGreetings :: User -> IO Response  
    
  • Monaden und Effektkontrolle

    • Mit Typeclasses und Monaden lässt sich präzise kodieren, welche Effekte eine Funktion ausführen darf
    • Das verhindert unbeabsichtigte Nebeneffekte und erhöht die Stabilität des Codes
  • Faktoren für höhere Produktivität

    • Das mächtige Typsystem und der rein funktionale Charakter erleichtern Code-Wiederverwendung und die Verallgemeinerung von Konzepten
    • Mit Konzepten wie Functor und Monoid lassen sich dieselben Muster auf verschiedene Datenstrukturen anwenden
    fmap (+2) [1, 2, 3] -- [3, 4, 5]  
    fmap (+2) (Just 2) -- Just 4  
    
  • Refactoring ohne Angst

    • Durch die Strenge des Compilers ist das Risiko geringer, bei Codeänderungen neue Bugs einzuführen
    • Das Typsystem ermöglicht es, die Domäne eines Programms präzise auszudrücken, sodass man Code mit mehr Sicherheit ändern kann
  • Besseres Verständnis des Programms

    • Mit deklarativer Programmierung lässt sich die Problemdomäne präzise ausdrücken
    • Die Bedeutung des Programms wird leichter verständlich und seine Zuverlässigkeit steigt
    • Unnötige Komplexität wird entfernt, wodurch eine vernünftige Argumentation über das Programm möglich wird
  • Algebraische Datentypen und Typeclasses

    • Innerhalb von Haskell lassen sich domänenspezifische Sprachen aufbauen
    • Das hilft dabei, Programme zu verstehen und zu warten
  • Beispielprogramm

    • Durch das Schreiben eines einfachen Buchhaltungstools werden Haskell-Konzepte praktisch angewendet

Epilog

  • Haskell zu verwenden macht Spaß und ist produktiv
  • Die Kombination aus einem starken, ausdrucksstarken Typsystem und reiner funktionaler Programmierung macht Haskell besonders
  • Andere Sprachen führen solche Funktionen ebenfalls ein, aber in Haskell sind diese Eigenschaften grundlegend verankert
  • Haskell zu lernen wird Ihre Denkweise über Programmierung verändern

Meinung von GN⁺

  • Der Lernwert von Haskell

    • Es hilft dabei, den eigenen Horizont als Programmierer zu erweitern
    • Wer das funktionale Programmierparadigma versteht, kann auch in anderen Sprachen besseren Code schreiben
  • Der Aufstieg funktionaler Programmierung

    • Sie hat Stärken bei Parallelverarbeitung und Nebenläufigkeit und passt daher gut zu modernen Computing-Umgebungen
    • Durch die Kontrolle von Nebeneffekten lässt sich vorhersagbarer Code schreiben
  • Vergleich mit anderen Sprachen

    • Es gibt auch Sprachen wie Rust oder Scala, die funktionale Programmierung unterstützen, aber Haskells Reinheit und Typsystem sind einzigartig
    • Beim Lernen neuer Sprachen können Haskell-Konzepte hilfreich sein
  • Praxistauglichkeit

    • Die anfängliche Lernkurve ist steil, aber die Produktivität steigt entsprechend der investierten Zeit
    • Nützlich ist es besonders in komplexen Systemen oder fehlerkritischen Domänen
  • Community und Ökosystem

    • Die Haskell-Community ist aktiv, und es werden kontinuierlich verschiedene Bibliotheken und Tools entwickelt
    • Durch die Teilnahme an Open-Source-Projekten kann man die eigenen Fähigkeiten verbessern

3 Kommentare

 
cosine20 2024-09-19

Ich habe mit F# begonnen, das um Praxisnähe ergänzt wurde.

 
savvykang 2024-09-13

ADT und Pattern Matching sind gut, aber bitte verschont mich mit Gerede über Monaden und Funktoren.

 
GN⁺ 2024-09-13
Hacker-News-Kommentare
  • Haskell erzwingt das Schreiben totaler Funktionen statt partieller Funktionen

    • Haskell verhindert keine unendliche Rekursion
    • In FP-Ökosystemen, die sich in Richtung abhängiger Typen bewegen, ist es wichtig sicherzustellen, dass der Typprüfer nicht unendlich läuft
    • Viele provisorische Erweiterungen in Haskell verursachen Probleme
    • Wenn man die Haskell-Philosophie mag, sollte man sich nicht nur auf Haskell beschränken
    • Die Standardisierung von Haskell ist gescheitert
    • Das einzigartige Wertversprechen von GHC könnte das GHC-Laufzeitsystem sein
  • Ich verwende Haskell seit 10 Jahren, und die Werkzeuge haben sich stark verbessert

    • ghcup, cabal-Sandboxing und HLS sind stabil
    • Ich habe in der Bibliothekslandschaft kaum viele Defizite festgestellt
    • Haskells Kompilierzeiten sind immer noch lästig
    • Die Kompilierzeit für Abhängigkeiten ist lang
  • Haskells Typsystem beweist nicht, dass Funktionen total sind

    • In der allgemeinen Programmierung sind Beweise für Totalität nicht besonders nützlich
    • Die meisten Menschen prüfen mit Tests, ob ein Programm tatsächlich funktioniert
  • Die Haskell-Sprache ist gut, aber das Ökosystem hat noch einen weiten Weg vor sich

    • Der Compiler ist langsam
    • Die Fähigkeit zur Fehlermeldung ist unzureichend
    • Der erste Fehler stoppt den Rest der Kompilierung
    • Die Werkzeuge sind im Vergleich zu anderen funktionalen Sprachen weiterhin schwach
    • Das Bibliotheksökosystem ist schwach
    • Haskells Ideen haben viele andere Sprachen beeinflusst
  • Ich möchte Haskell oder eine andere funktionale Sprache beruflich verwenden

    • Sprachen wie Go ließen sich leicht erlernen
    • Ich möchte lernen, wie man in funktionalen Sprachen eine Codebasis aufbaut
  • Haskell hat meine Denkweise beim Programmieren und die Code-Architektur stark beeinflusst

    • Haskells Typsystem ist sehr mächtig und leicht zu verstehen
    • Es hat Spaß gemacht, Haskell-Code mikrozuoptimieren
    • Die Werkzeuge sind weiterhin unzureichend
  • Haskell experimentiert auf Sprachebene mit Laziness

    • Laziness lässt sich auch auf Ebene der Standardbibliothek erreichen
  • Haskells extreme Reinheit und Unveränderlichkeit sind ein Problem

    • Viele Programmierer können prozedurale/veränderliche Schleifen leichter ausdrücken
    • Rust verwendet ein leistungsfähiges Typsystem und viele funktionale Idiome, erlaubt aber auch Schleifen und Veränderlichkeit
  • Haskell eignet sich sehr gut für Business-Logic-Software (BLOBS)

    • Mit einfachen Typen und Pattern Matching lässt sich der Großteil der Geschäftslogik modellieren
    • Wenn man die einfachen Teile beibehält, lässt es sich auch nichttechnischen Mitwirkenden leicht beibringen
    • Haskell macht Spaß