Meest gebruikelijk patroon voor het gebruik van een database in een functionele taal, gegeven het verlangen naar geen bijwerkingen?

Ik probeer mijn hoofd rond een kernconcept van functionele langauges te krijgen:

"Een centraal concept in functionele talen is dat het resultaat van een functie wordt bepaald door de invoer en alleen door de invoer.Er zijn geen neveneffecten!"

http://www.haskell.org/haskellwiki/Why_Haskell_matters#Functions_and_side-effects_in_functional_languages ​​

Mijn vraag is, als een functie alleen wijzigingen aanbrengt in de lokale omgeving en het resultaat retourneert, hoe kan het dan werken met een database of een bestandssysteem? Zou dat per definitie geen toegang kunnen krijgen tot wat in feite een globale variabele of globale toestand is?

Wat is het meest gebruikte patroon om dit te omzeilen of aan te pakken?

8
Goede antwoorden allemaal, dank je!
toegevoegd de auteur Allyl Isocyanate, de bron

3 antwoord

Alleen omdat een functionele taal functioneel is (misschien zelfs helemaal puur als Haskell!), Betekent dit niet dat programma's die in die taal zijn geschreven, puur moeten zijn als ze worden uitgevoerd.

De aanpak van Haskell, bijvoorbeeld wanneer het gaat om bijwerkingen, kan eenvoudig worden uitgelegd: laat het hele programma zelf zuiver zijn (wat betekent dat functies altijd dezelfde waarden voor dezelfde argumenten retourneren en geen bijwerking hebben), maar laat de retourwaarde van de functie main een actie zijn die kan worden uitgevoerd.

Probeert dit uit te leggen met pseudocode, hier is een programma in een gebiedende , niet-functionele taal:

main:
  read contents of abc.txt into mystring
  write contents of mystring to def.txt

De bovenstaande procedure main is: een reeks stappen die beschrijft hoe een reeks acties moet worden uitgevoerd.

Vergelijk dit met een puur functionele taal zoals Haskell. In functionele talen is alles een uitdrukking, inclusief de hoofdfunctie. Men kan dus het equivalent van het bovenstaande programma als volgt lezen:

main = the reading of abc.txt into mystring followed by
       the writing of mystring to def.txt

Dus main is een uitdrukking die, wanneer geëvalueerd, een actie retourneert die beschrijft wat te doen om het programma uit te voeren. De daadwerkelijke uitvoering van deze actie gebeurt buiten de programmeurswereld. En dit is echt hoe het werkt; het volgende is een echt Haskell-programma dat kan worden gecompileerd en uitgevoerd:

main = readFile "abc.txt" >>= \ mystring ->
       writeFile "def.txt" mystring

a >>= b can be said to mean "the action a followed by the result of a given to action b" in this situation, and the result of the operator is the combined actions a and b. The above program is of course not idiomatic Haskell; one can rewrite it as follows (removing the superfluous variable):

main = readFile "abc.txt" >>=
       writeFile "def.txt"

... of, met behulp van syntactische suiker en de do notatie:

main = do
  mystring <- readFile "abc.txt"
  writeFile "def.txt" mystring

Alle bovenstaande programma's zijn niet alleen gelijkwaardig, maar ze zijn identiek voor zover het de compiler betreft.

Dit is hoe bestanden, databasesystemen en webservers kunnen worden geschreven als puur functionele programma's: door actiewaarden door het programma te leiden zodat ze worden gecombineerd en uiteindelijk in de functie main terechtkomen. Dit geeft de programmeur een enorme controle over het programma en daarom zijn puur functionele programmeertalen in sommige situaties zo aantrekkelijk.

10
toegevoegd

Het meest voorkomende patroon voor het omgaan met bijwerkingen en onzuiverheden in functionele talen is:

  • wees pragmatisch, geen purist
  • bieden ingebouwde ins die onreine code en bijwerkingen mogelijk maken
  • gebruik ze zo min mogelijk!

Voorbeelden:

  • Lisp/Scheme: set!
  • Clojure: refs, and using mutating methods on java objects
  • Scala: creating variables with var
  • ML: not sure of specifics, but Wikipedia says it allows some impurity

Haskell bedriegt een klein beetje - de oplossing is dat voor functies die toegang hebben tot het bestandssysteem of de database, de status van het hele universum op dat moment , inclusief de status van het bestandssysteem/db , worden doorgegeven aan de functie. (1) Als u dus de status van het hele universum op dat moment kunt repliceren, kunt u dezelfde resultaten tweemaal van dergelijke een functie. Natuurlijk kun je op dat moment de status van het hele universum niet repliceren , en dus geven de functies verschillende waarden terug ...

Maar de oplossing van Haskell, IMHO, is niet de meest voorkomende.


(1) Not sure of the specifics here. Thanks to CAMcCann for pointing out that this metaphor is overused and maybe not all that accurate.

5
toegevoegd
Universe maakt het moeilijker dan het is, want zijn context is een DB. Het is heel goed mogelijk, en als je event sourcing gebruikt, kun je de staat ook in het verleden krijgen. Grondstofintensief, maar we hebben het hier over functioneel.
toegevoegd de auteur Justin Dennahower, de bron
Voor wat het waard is, is dat niet hoe Hasjell werkt in Haskell, hoewel dat een veelgebruikte metafoor is. Het enige wat er echt aan de hand is, is dat het type systeem wordt gebruikt om ervoor te zorgen dat onzuivere functies als zodanig worden gemarkeerd en in een goed gedefinieerde volgorde worden uitgevoerd. De metafoor 'de staat van het universum passeren' wordt gebruikt bij de implementatie hiervan, maar conceptueel houdt deze niet goed stand bij nader inzien.
toegevoegd de auteur C. A. McCann, de bron

Het toevoegen van een database verschilt niet van andere gevallen van invoer/uitvoer, zoals afdrukken (17) .

In gretig geëvalueerde talen, zoals LISP en ML, gebruikt de gebruikelijke aanpak voor effectief programmeren gewoon neveneffecten, zoals in de meeste andere programmeertalen.

In Haskell is de oplossing voor het IO-probleem het gebruik van monaden. Als u bijvoorbeeld HDBC , een haskell-databankenbibliotheek, je kunt veel functies daar zien die IO-acties retourneren.

Sommige talen, zoals Clean, gebruiken uniciteitssoorten om dezelfde soort volgzaamheid toe te passen die Haskell met monaden hanteert, maar deze talen zijn tegenwoordig moeilijker te vinden.