In der Funktionalen Programmierung wird ein gegebenes Problem gelöst, indem dafür eine Funktion formuliert wird. Die Abarbeitung eines funktionalen Programmes erfolgt in Form der Auswertung der das Problem beschreibenden Funktion. Hier liegt der entscheidende Unterschied zu imperativen Programmiersprachen wie C oder Java, in denen die Abarbeitung eines Programmes gleichbedeutend ist mit der Abarbeitung einer Sequenz von Anweisungen.
Während die Aufgabe des Programmierers in der Definition der das Problem beschreibenden Funktion und ihrer Teilfunktionen liegt, ist der Computer in der funktionalen Programmierung ein Rechner im (fast) ursprünglichen Sinne: seine Hauptaufgabe besteht in der Auswertung (also in der Bestimmung des Wertes) von Ausdrücken.
Damit die Formulierung komplexer Probleme in Form von Ausdrücken funktionieren kann, müssen die Möglichkeiten der Ausdrucksformulierung ein wenig über die eines einfachen Taschenrechners hinausgehen. Dazu können vom Programmierer Definitionen aufgestellt werden, die Ausdrücken Namen zuordnen. Der Computer begreift diese Definitionen als Ersetzungsregeln und ersetzt, sofern er bei der Auswertung eines Ausdruckes auf einen solchen Namen stösst, diesen durch die zugehörige Definition.
Haskell ist eine funktionale Programmiersprache. Die Abarbeitung eines Haskell-Programmes erfolgt also in der oben geschilderten Weise, nämlich als Auswertung einer das Problem beschreibenden Funktion.
Bei der Auswertung eines Ausdruckes werden nur diejenigen Berechnungen ausgeführt, deren Ergebnis auch benötigt wird. Ausdrücke deren Auswertung zur Lösung des Problems nicht notwendig sind, werden nicht ausgewertet. Dieses Prinzip nennt man "lazy evaluation" oder auch "call by name". Es beinhaltet auch, dass Berechnungen erst zu dem Zeitpunkt durchgeführt werden, in dem sie tatsächlich gebraucht werden. Dadurch können zum Beispiel unendlich lange Listen (im Gegensatz zu vielen anderen Programmiersprachen) definiert werden, so lange immer nur ein endlicher Teil davon tatsächlich benutzt wird.
Wie in jeder funktionalen Programmiersprache existieren auch in Haskell grundsätzlich keine Seiteneffekte, wie z.B. Veränderungen globaler Variablen . Eine Programmiersprache ohne Seiteneffekte wäre aber nicht sinnvoll zu nutzen, da z.B. Bildschirm- oder Dateiausgaben ebenfalls als Seiteneffekte anzusehen sind. In Haskell werden daher alle nicht-reinen Operationen in sogenannte Monaden gekapselt und vom Rest des Programmes isoliert ausgeführt.
Sogenannte "destructive updates" (x = x + 1
) sind in Haskell nicht möglich: Ein Bezeichner x ist in Haskell ein Name und keine Variable. Der hinter dem Bezeichner stehende Wert kann im Programmablauf nicht verändert werden, d.h. Zuweisungen im herkömmlichen Sinne existieren nicht. Damit sind auch Schleifen nicht nutzbar, da Schleifenzähler oder Abbruchkriterien nicht formuliert werden können.
Aus der Abwesenheit von "destructive updates" einerseits und Seiteneffekten andererseits ergibt sich eine Verlässlichkeit bezgl. der Resultate von Funktionsaufrufen, unabhängig vom Zeitpunkt der Auswertung: Wird eine Funktion f mit einem Argument a zu einem Zeitpunkt t1 ausgewertet, so ergibt sich ganz sicher dasselbe Resultat wie bei der Auswertung von f mit a in t2. Denn a ändert sich im Zeitablauf nicht und f hat keine Seiteneffekte. Das Resultat eines Funktionsaufrufes ist also ausschliesslich abhängig vom Wert der Argumente.
Haskell wird desöfteren als "ausführbare Spezifikationssprache" bezeichnet. Spezifikationen sollen so klar und formal wie möglich ausdrücken, was ein Programm tun soll. Funktionen können meist gut durch die formale Beschreibung ihrer Zuordnungsvorschrift spezifiziert werden. Wenn dies in der Notation von Haskell geschieht, ist die Spezifikation zugleich schon ausführbares Programm.
Die Motivation, Haskell in manchen Anwendungsgebieten einer imperativen Programmiersprache vorzuziehen (abgesehen von dem durchaus interessanten theoretisch-mathematischen Konzept), ist für viele Leute, damit kürzere, fehlerfreiere Programme in kürzerer Zeit schreiben zu können. Dabei ist Haskell sicherlich schwieriger zu debuggen als imperative Programmiersprachen, aber dafür fehlen in Haskell auch viele der verbreiteten Fehlerquellen.