Haskell (programmeertaal)

Haskell
Haskell
Paradigma puur functioneel
Verschenen 1990
Ontwikkeld door Simon Peyton Jones, Paul Hudak, Philip Wadler en anderen
Huidige versie Haskell 2010 (juli 2010)
Typesysteem statisch, sterk, inferred
Implementaties GHC, Hugs en anderen
Dialecten Helium, Gofer
Beïnvloed door Lisp, APL, Hope, Miranda, ML, Id
Invloed op C#, Curry, F#, LINQ, Perl 6, Python, Scala
Besturingssysteem Multiplatform
Bestandsextensies .hs, .lhs
Website https://haskell.org/
Portaal  Portaalicoon   Informatica

Haskell is een functionele programmeertaal vernoemd naar de wiskundige Haskell Brooks Curry.

Aan Haskell wordt voornamelijk gewerkt aan de Universiteit van Glasgow.

Door het verschijnen van de programmeertaal Miranda in 1985 (uitgebracht door Research Software Ltd.) steeg de interesse in luie functionele talen. Tegen 1987 waren er al een heleboel functionele talen in gebruik. Miranda was de meest verspreide taal, maar was propriëtaire software. Op de Internationale Conferentie over Functionele Talen in 1987 te Portland heerste consensus dat een open standaard voor dergelijke talen opgesteld moest worden. Het doel van de commissie was bestaande functionele consolideren tot een gemeenschappelijke taal die moest dienen als basis voor verder onderzoek naar functionele talen.[1]

Haskell 1.0 tot 1.4

[bewerken | brontekst bewerken]

De eerste versie van Haskell, Haskell 1.0, is opgesteld in 1990. Het werk van de commissie resulteerde in reeks taaldefinities (1.0, 1.1, 1.2, 1.3 en 1.4).[2]

Eind 1997 resulteerde de reeks definities in Haskell 98, met als doel een stabiele, minimale, draagbare versie van de taal en bijhorende standaard te publiceren. De commissie verwachtte en maakte het expliciet mogelijk om extensies toe te voegen aan de taal via experimentele functies.[1]

In februari 1999 werd de standaard voor Haskell 98 gepubliceerd als The Haskell 98 Report. In januari 2003 werd een herziene editie gepubliceerd als Haskell 98 Language and Libraries: The Revised Report.[1] De taal blijft zich sterk ontwikkelen. De Glasgow Haskell Compiler is de facto de standaardimplementatie.[3]

Begin 2006 werden de eerste stappen gezet om een opvolger voor Haskell 98 te maken, onder de naam Haskell Prime.[4] Het doel was incrementele updates te produceren, met hoogstens één nieuwe versie per jaar. De eerste revisie, Haskell 2010, is aangekondigd in november 2009 en gepubliceerd in juli 2010.[5]

Haskell 2010 is een incrementele update, die verschillende vaak gebruikte en niet-controversiële functies toevoegt, die voorheen via compilervlaggen aangezet moesten worden:

  • Hiërarchische modulenamen., bv. Data.List in plaats van List. Deze functionaliteit is oorspronkelijk toegevoegd aan Haskell 98 middels een addendum en wordt universeel gebruikt.
  • Met de foreign function interface is het mogelijk om andere programmeertalen aan te spreken. In de standaard zijn enkel bindingen naar C gedefinieerd, maar het ontwerp laat andere talen toe. Ook deze functie was oorspronkelijk een addendum bij Haskell 98.
  • De zogenaamde -patronen zijn niet meer toegelaten.
  • De regels omtrent de type-inferentie zijn versoepeld teneinde meer mogelijkheden te geven aan programma's.
  • Enkele syntaxisproblemen zijn verholpen.
  • De pragma LANGUAGE is toegevoegd om beter met extensies te kunnen werken.

Implementaties

[bewerken | brontekst bewerken]

Parallel aan de ontwikkeling van de theoretische Haskell-taal is er een aantal werkomgevingen voor Haskell ontwikkeld. De bekendste hiervan zijn de Hugs- en Gofer-systemen en de Glasgow Haskell Compiler, die alle gratis beschikbaar worden gesteld door de universitaire teams die eraan werken. Speciaal voor het leren van Haskell heeft men aan de Universiteit van Utrecht Helium ontwikkeld waarbij men aandacht heeft besteed aan de duidelijkheid van de foutmeldingen.

In Nijmegen is de programmeertaal Clean ontwikkeld, die zeer sterk op Haskell lijkt, maar de programmeur meer controle over de luie evaluatie geeft.

Functionele basis

[bewerken | brontekst bewerken]

In tegenstelling tot vele bekende programmeertalen zoals C, C++ en Java is Haskell geen imperatieve taal, maar een functionele taal. Dat wil zeggen dat de taal niet gebaseerd is op het turingmachine-model van berekening, maar op het Lambdacalculusmodel van Alonzo Church waarin het toepassen van functies op termen en termenreductie de basis is van berekening.

Haskell is een luie ("lazy"), puur functionele taal. Puur functioneel zijn wil zeggen dat erin gedefinieerde functies geen neveneffecten kunnen vertonen. Voorbeelden van niet-pure functionele programmeertalen zijn Standaard ML en Scheme. Een luie functionele taal gebruikt luie evaluatie om te voorkomen dat resultaten die niet gebruikt worden, berekend worden. Hoewel het niet door iedereen als een intuïtieve eigenschap wordt aangezien, wordt luie evaluatie beschouwd als een manier om meer modularisatie te kunnen realiseren.

De programmeertaal is sterk en statisch getypeerd (typefouten kunnen tijdens de uitvoering van een programma niet optreden), en steunt sterk op type-inferentie (meestal kunnen de types van functies en variabelen door de compiler ontdekt worden). Het typesysteem is zeer uitgebreid, en ondersteunt het concept van klassen van types, waarbij deze klassen van elkaar afgeleid kunnen worden.

module Main (main) where            -- niet nodig bij interpreter, standaard bij modulebestanden  main :: IO ()                       -- optioneel, de compiler kan dit bepalen main = putStrLn "Hello, World!" 

De onderstaande functie berekent de faculteit van een getal. De functie is voor negatieve waarden ongedefinieerd. Ze is gedefinieerd op enkele verschillende manieren:

 -- Type-annotatie (optioneel, zelfde voor elke implementatie) faculteit :: (Integral a) => a -> a  -- Middels recursie (met de "ifthenelse"-expressie) faculteit n = if n < 2               then 1               else n * faculteit (n - 1)  -- Met recursie (met patroonvergelijking) faculteit 0 = 1 faculteit n = n * faculteit (n - 1)  -- Met recursie (met guards) faculteit n    | n < 2     = 1    | otherwise = n * faculteit (n - 1)  -- Met een lijst en de "product"-functie faculteit n = product [1..n]  -- Met fold (implementeert "product") faculteit n = foldl (*) 1 [1..n]  -- In "point-free"-stijl faculteit = foldr (*) 1 . enumFromTo 1 

Invoegen in een lijst

[bewerken | brontekst bewerken]

De volgende functie voegt een getal in een lijst in, op volgorde van klein naar groot:

insert :: Int -> [Int] -> [Int] insert a [] = [a] insert a list@(x:xs) | a <= x = a : list                      | a >  x = x : insert a xs 

Bij het invoegen van een getal zijn er twee gevallen te onderscheiden: het invoegen van een getal in een lege lijst en in een lijst met één of meerdere getallen. Het invoegen in de lege lijst is eenvoudig want dat is een lijst met dat getal. Bij het invoegen van een getal in een gevulde lijst kijken we naar het eerste getal, x, en de rest, xs. Als het in te voegen getal kleiner of gelijk is aan het eerste getal, dan zetten we het getal op kop van de hele lijst. Als het getal groter is dan het eerste getal dan nemen we het eerste element en voegen we het getal in de rest van de lijst in. Op deze manier wordt de lijst doorlopen totdat de plek is gevonden waar het getal neergezet kan worden.

Hogere-ordefuncties en luie evaluatie

[bewerken | brontekst bewerken]

In Haskell kan men hogere-ordefuncties gebruiken, dit zijn functies die een of meerdere functie(s) als argument meekrijgen of die een functie opleveren. Voorbeelden hiervan zijn map, filter en fold. De functie filter krijgt bijvoorbeeld een functie mee (een predicaat) en een lijst. Deze functie levert een lijst op waarin alleen de elementen zitten uit de gegeven lijst die aan het predicaat voldoen. Bijvoorbeeld:

filter even [0..] 

Het bovenstaande levert een oneindige lijst op met even getallen (formeler: alle elementen uit de lijst [0, 1, 2, ..] waarvoor de functie even de waarde True teruggeeft). Het feit dat deze lijst oneindig is, is geen probleem, want de lijst hoeft, vanwege het feit dat Haskell luie evaluatie toepast, alleen maar opgebouwd te worden indien nodig. Zo kan men schrijven:

take 10 (filter isPriem [1..]) 

De functie take levert de eerste n elementen van een lijst op. Als men de functie isPriem heeft gedefinieerd (die voor een getal bepaalt of het een priemgetal is) dan levert het bovenstaande de eerste 10 priemgetallen op.

Een greep uit de applicaties die geschreven zijn in of gebruik maken van Haskell:

In 2002 en 2003 bespraken respectievelijk Jan-Willem Maessen en Simon Peyton Jones problemen geassocieerd met luie evaluatie. Naast de praktische overwegingen, zoals betere performantie, maakte luie evaluatie het moeilijker voor programmeurs om over de code te redeneren.[11][12]

Anderen observeerden dat Haskell niet eenvoudig is om te leren voor beginners:[13]

The subtle syntax and sophisticated type system of Haskell are a double edged sword – highly appreciated by experienced programmers but also a source of frustration among beginners, since the generality of Haskell often leads to cryptic error messages.

Dit was ook een van de redenen om Helium te maken.

Gerelateerde talen

[bewerken | brontekst bewerken]

Clean is een nauw verwante, maar iets oudere taal van Haskell.

Een reeks talen die geïnspireerd zijn door Haskell, maar met verschillend typesysteem, zijn o.a.:

[bewerken | brontekst bewerken]