I hvilket år dukket haskel opp. "Og hvem har laget det?" Funksjoner av funksjonelle språk

Syntaksen for to påfølgende identifikatorer betyr å bruke funksjonen foo på argumentlinjen:

I Haskell krever ikke å kalle en funksjon parentes rundt argumentet.

Klammer brukes til å gruppere argumenter:

acos (cos pi)

Multiple argument funksjon:

maks 5 42

Operasjonen med å bruke en funksjon er assosiativ til venstre:

(maks 5) 42

Funksjon maks brukes sekvensielt på to argumenter.
Kompilatoren forstår konstruksjonen f x y hvordan (f x) y, og ikke omvendt f (x y).

Uttrykk (maks 5) dette er den såkalte delfunksjonsapplikasjonen. V generelt syn det kan formuleres som følger: hvis vi har en funksjon av N variabler og vi ser på det som en funksjon av N variabler, så kan vi se på det fra den andre siden og si at det er en funksjon av en variabel som returnerer oss en funksjon av N - 1 variabler.

3 + synd 42

3 + (maks 5) 42

Syntaks for egendefinert funksjonserklæring

En funksjon som summerer kvadratene til de to argumentene som sendes til den:

SumSquares x y = x ^ 2 + y ^ 2 rock "n" roll = 42


Funksjonsnavnet og formelle parameternavn må begynne med små bokstaver. Og store bokstaver brukes til å definere datatyper.

En funksjon med tre argumenter som beregner lengden på en 3D-vektor:

LenVec3 x y z = sqrt (x ^ 2 + y ^ 2 + z ^ 2)


For å definere en funksjon i GHCi-tolken må vi bruke let nøkkelordet.

La sumkvadrater x y = x ^ 2 + y ^ 2

Funksjon renhet egenskap

En viktig egenskap som skiller funksjonelle språk fra imperative språk er egenskapen til funksjonsrenhet. Alle funksjoner i Haskell er rene. Dette betyr at verdien av funksjonen er fullstendig bestemt av verdiene til argumentene som sendes til den. Ingen andre datakilder kan påvirke resultatet som returneres av funksjonen. Hvis du trenger en funksjon for å ta data fra et sted, må du sende denne datakilden til den som et argument.

En funksjon som ikke tar noen argumenter er en konstant. En slik funksjon returnerer den samme verdien hele tiden, uansett omstendigheter.

Prelude> la fortyTwo = 39 + 3 Prelude> fortyTwo 42

I Haskell kan du ikke definere en funksjon som ikke tar noen argumenter og returnerer forskjellige verdier for forskjellige anrop.

Mekanisme for å definere funksjoner ved bruk av delvis applikasjon

Vi kan se på hvilken som helst funksjon som en funksjon av ett argument som returnerer en funksjon.

Prelude> la max5 x = max 5 x Prelude> max5 4 5 Prelude> max5 42 42


Alternativ syntaks for å definere en funksjon:

Prelude> let max5 "= max 5 Prelude> max5" 4 5 Prelude> max5 "42 42

Vi har forkortet ekstraargumentet x på venstre og høyre side. Og de skrev at funksjonen max5 "bare er en delvis anvendt funksjon maks. Dermed kan du definere en funksjon uten å spesifisere alle argumentene. Den tilsvarende programmeringsstilen kalles meningsløs.

Ofte er utformingen av funksjoner i Haskell innstilt på en slik måte at delvis påføring er praktisk;

Prelude> la rabatt begrense proc sum = if sum> = limit then sum * (100 - proc) / 100 else sum Prelude> la standardRabatt = rabatt 1000 5 Prelude> standardRabatt 2000 1900,0 Prelude> standardRabatt 900 900,0

Grense- og proc-parametrene endres sjelden. Sumparameteren endres imidlertid ofte. Faktisk, hver gang denne funksjonen blir kalt.

Anta at vi utvikler et oversettelsessystemgrensesnitt for naturlige språk i Haskell. Den må inneholde en oversettelsesfunksjon med tekst, languageFrom og languageTo parametere. For å gjøre det praktisk å implementere følgende funksjoner:

  • oversett fra spansk til russisk,
  • oversett fra engelsk til russisk
  • og oversett til russisk
du må ordne parametrene i følgende rekkefølge: oversett språkTil språkFra tekst.

Skriv operator ->

For å skrive typen til en funksjon, må du skrive typen argument og typen resultat av denne funksjonen. I Haskell, for å beskrive typen av en funksjon, er operatoren -> en binær operator der venstre operand er typen argument, og høyre operand er typen av resultatet. Pilen er mellom venstre og høyre operand t, k, dette er en infiksoperator.

Prelude>: t not not :: Bool -> Bool Prelude> (&&) False True False Prelude> ((&&) False) True False

Typen av det siste uttrykket kan skrives som følger:
Bool -> (Bool -> Bool)
Typeoperatøren anses som rettassosiativ. Derfor kan Bool -> (Bool -> Bool) skrives om som Bool -> Bool -> Bool

Preludium>: t (&&) (&&) :: Bool -> Bool -> Bool

La oss huske rabattfunksjonen, som kom tilbake totale mengden kjøp med mulig rabatt. Som parametere ble det passert beløpet uten rabattsummen, prosentandelen av rabattprocen, og rabatten ble belastet hvis det overførte beløpet overstiger grenseterskelen. Alle disse parameterne, så vel som returverdien, kan lagres i Double-typen. Funksjonstypen kan spesifiseres i kildefilen sammen med dens definisjon:

rabatt :: Dobbel -> Dobbel -> Dobbel -> Dobbel rabattgrense proc sum = if sum> = limit then sum * (100 - proc) / 100 else sum

Merk at typedeklarasjonen er valgfri, selv om den ofte anbefales for dokumentasjonsformål. Det er vanligvis plassert foran funksjonsdefinisjonen, selv om denne erklæringen toppnivå kan plasseres hvor som helst i kildefilen.

Standardrabatt :: Dobbel -> Dobbel standardrabatt = rabatt 1000 5

Tenk på funksjonen twoDigits2Int, som tar to tegn og returnerer et tall sammensatt av disse tegnene hvis begge tegnene er numeriske, og 100 er ellers... (Det første tegnet behandles som antall tiere, det andre som antall enheter.)

Importer Data.Char twoDigits2Int :: Char -> Char -> Int twoDigits2Int x y = if isDigit x && isDigit y then digitToInt x * 10 + digitToInt y else 100


GHCi> twoDigits2Int "4" "2" 42

Rekursjon

I imperative språk er en loop hovedelementet i repeterende beregning. I funksjonelle språk er loops lite meningsfylt. Siden funksjonelle språk mangler konseptet med en foranderlig variabel, er det ingen måte å skille en loop-iterasjon fra en annen. For å utføre repeterende beregninger i funksjonelle språk, brukes rekursjon. For å forhindre at en rekursiv funksjon går i loop, må den oppfylle følgende krav:
  • funksjonsanrop på høyre side må utføres på andre parameterverdier enn formell parameter funksjoner;
  • rekursive samtaler må avbrytes et sted (det må være en såkalt terminerende tilstand).

Faktoriell

Faktoriell n = hvis n == 0 så 1 annet n * faktoriell (n - 1)


Implementering av beregning av faktoren ved å bruke akkumuleringsparameteren:

Faktoriell5 n | n> = 0 = hjelper 1 n | ellers = feil "arg må være> = 0" hjelper acc 0 = acc hjelper acc n = hjelper (acc * n) (n - 1)

En slik implementering i tilfelle av en faktoriell gir ingen ekstra fordeler, men veldig ofte kan slike implementeringer forbedre effektiviteten til rekursive funksjoner. I mange tilfeller, i rekursive funksjoner, ved å gi en direkte definisjon av en rekursiv funksjon i form av seg selv, kan man oppnå kvadratisk eller høyere polynomisk asymptotikk. Og når det gjelder bruk av hjelpefunksjoner, er det veldig ofte mulig å korrigere asymptotikken ved å redusere den til lineær.

Dobbel faktorial

Tenk på en funksjon som beregner en dobbel faktorial, det vil si produktet av naturlige tall som ikke overskrider et gitt tall og har samme paritet. For eksempel: 7 !! = 7⋅5⋅3⋅1, 8 !! = 8⋅6⋅4⋅2. Det antas at funksjonsargumentet bare kan ha ikke-negative verdier.

DoubleFact :: Heltall -> Heltall doubleFact n = hvis n<= 0 then 1 else n * doubleFact (n - 2 )

Fibonacci tallrekke

I Haskell er denne definisjonen gitt av følgende funksjon:

Fibonacci :: Heltall -> Heltall fibonacci n | n == 0 = 0 | n == 1 = 1 | n> 1 = fibonacci (n - 1) + fibonacci (n - 2) | n< 0 = fibonacci (n + 2 ) - fibonacci (n + 1 ) | otherwise = undefined

Implementeringen av funksjonen for å beregne Fibonacci-tallet, basert på en direkte rekursiv definisjon, er ekstremt ineffektiv - antall funksjonskall vokser eksponentielt med veksten av argumentverdien. GHCi lar deg spore minnebruk og tid brukt på å evaluere et uttrykk ved å utføre kommandoen: set + s:

* Fibonacci>: sett + s * Fibonacci> fibonacci 30 832040 (16,78 sekunder, 409, 318, 904 byte)

Ved å bruke akkumulatormekanismen kan du skrive en mer effektiv implementering som har lineær kompleksitet (etter antall rekursive anrop):

Fibonacci ":: Heltall -> Heltall fibonacci" n = hjelper n 0 1 hjelper n a b | n == 0 = a | n> 0 = hjelper (n - 1) b (a + b) | n< 0 = helper (n + 1 ) b (a - b) | otherwise = undefined


Funksjoner av høyere orden

En høyere-ordens funksjon er en funksjon som tar en annen funksjon som argument. Funksjoner av høyere orden er sjeldne i imperative språk. Et eksempel er sorteringsfunksjonen fra C Standard Library. Som det første argumentet sendes et binært sammenligningspredikat til sorteringsfunksjonen ved hjelp av hvilken en matrise sendes som det andre argumentet og sorteres. På funksjonelle språk og på Haskell funksjoner høyere ordre brukes veldig ofte.

Preludium>: t ($) ($) :: (a -> b) -> a -> b

Det er en polymorf type. Dollaroperatoren er en funksjon av to argumenter. Dens venstre operand eller første argument (a -> b) er en funksjon. Dens høyre operand a er en vilkårlig verdi. Dollaroperatoren bruker ganske enkelt det første argumentet (a -> b) på det andre argumentet a. Derfor er det her nødvendig at typene er konsistente. Typen av det andre argumentet til dollaroperatoren må samsvare med typen parameter for funksjonen som sendes i det første argumentet. Dessuten er resultatet av å utføre dollaroperatoren resultatet av funksjonen som ble sendt som det første argumentet. Siden resultatets type er b, er resultatet av dollarsetningen type b.

Følgende bruk er kun gyldig når a og b er like.

Prelude> la gjelde2 fx = f (fx) Prelude>: t apply2 apply2 :: (t -> t) -> t -> t Prelude> apply2 (+ 5) 22 32 Prelude> apply2 (++ "AB") " CD "" CDABAB "

Det første argumentet er faktisk en funksjon, men argumentet og returverdien er av samme type. Og det andre argumentet er verdien av denne typen, og returverdien er også verdien av denne typen. Dermed kan applicer2-funksjonen brukes på et mer begrenset sett med funksjoner enn dollar. Hvis dollar er polymorf i argument og returverdi, så er application2 polymorf i bare én parameter.

Flip-funksjonen fra standardbiblioteket er definert som følger: flip f y x = f x y.

Prelude> flip (/) 4 2 0.5 Prelude> (/) 4 2 2.0 Prelude> flip const 5 True True Prelude>: t flip flip :: (a -> b -> c) -> b -> a -> c Preludium>: t flip const flip const :: b -> c -> c

(- En nyttig funksjon er definert i Data.Function-modulen høyere ordre -} på :: (b -> b -> c) -> (a -> b) -> a -> a -> c på op f x y = f x `op` f y (- Det krever fire argumenter: 1) binær operator med samme type argumenter (type b), 2) en funksjon f :: a -> b som returnerer en verdi av typen b, 3,4) og to verdier av type a. På-funksjonen gjelder f to ganger på to verdier av type a og sender resultatet til en binær operator. Ved å bruke on kan du for eksempel skrive funksjonen til å summere kvadratene til argumentene slik :-) sumSquares = (+) `på` (^ 2) (- MultiSecond-funksjonen, som multipliserer de andre elementene av par, implementeres som følger -) multSecond = g `på` h g = (*) h = snd

Anonyme funksjoner

I Haskell, som i matematikk, er funksjoner vanligvis navngitt. Når vi skal kalle en funksjon, refererer vi til den ved navn. Det finnes imidlertid en alternativ tilnærming kalt anonyme funksjoner.

Preludium> (\ x -> 2 * x + 7) 10 27 Prelude> let f "= (\ x -> 2 * x + 7) Prelude> f" 10 27

den anonym funksjon eller en lambdafunksjon.

Det er syntaktisk sukker for å forenkle notasjonen.

Preludium> la lenVec xy = sqrt $ x ^ 2 + y ^ 2 Prelude> la lenVec x = \ y -> sqrt $ x ^ 2 + y ^ 2 Prelude> la lenVec = \ x -> \ y -> sqrt $ x ^ 2 + y ^ 2 Prelude> lenVec 3 4 5.0 Prelude> la lenVec = \ xy -> sqrt $ x ^ 2 + y ^ 2 Prelude> lenVec 3 4 5.0


Anonyme funksjoner brukes ved bruk av høyere ordensfunksjoner.

(- Funksjon on3, har lignende semantikk som on, men tar en tre-plassers funksjon som sitt første argument -) on3 :: (b -> b -> b -> c) -> (a -> b) -> a -> a -> a -> c on3 op f x y z = op (f x) (f y) (f z) (- Summen av kvadratene av tre tall kan skrives med on3 slik -) sum3squares = (\ x y z -> x + y + z) `on3` (^ 2)

Curried og uncurried funksjoner

Med syntaksen for å kalle opp funksjoner i Haskell, kan du liste opp ikke alle argumentene, men bare deler av dem. De første par argumentene til en funksjon kan spesifiseres, og resten kan forkastes. Denne ideen om delvis bruk av funksjoner ble oppfunnet av Haskell Curry, og til hans ære kalles slike funksjoner med argumenter vedtatt en etter en curried. I Haskell er ikke alle funksjoner curry. I Haskell kan du definere funksjoner på tupler. I dette tilfellet vil syntaksen for å ringe funksjoner se ut som på vanlige språk:
funksjonsnavn (første_argument, andre_argument)

Preludium> fst (1, 2) 1


Currying er fremgangsmåten for å gå fra ikke-curried-funksjoner til funksjoner som tar argumenter ett om gangen. Tenk deg at vi har en funksjon av høyere orden, som på kombinatoren, den forventer at 2 av de 4 argumentene er en funksjon. Det første argumentet er en to-argument funksjon som er curried. Haskell har en spesiell karrikombinator som går over fra en ukurert funksjon til en karri. I det følgende eksempelet gjør curry funksjonen spesifisert på et par til en standard curried-funksjon med to argumenter.

* Demo>: t on on :: (b -> b -> c) -> (a -> b) -> a -> a -> c * Demo>: t curry fst `on` (^ 2) curry fst `on` (^ 2) :: Antall b => b -> b -> b


Et annet eksempel, en uncurried avg-funksjon:

Gj.sn. :: (dobbel, dobbel) -> dobbel snitt p = (fst p + snd p) / 2

Curry avg 'on' (^ 2) funksjonen er en funksjon som beregner gjennomsnittet av kvadratene av de to verdiene som er sendt til den.

Karrifunksjonen er:

Preludium> let cur fxy = f (x, y) Prelude>: t cur cur :: ((t1, t2) -> t) -> t1 -> t2 -> t Prelude>: t curry curry :: ((a) , b) -> c) -> a -> b -> c

Det tar en uregelmessig funksjon som sitt første argument, dvs. funksjon over et par, men gjør den som en returverdi til en curried funksjon der argumentene sendes sekvensielt.

Det er invers funksjon uncurry:

Preludium>: t uncurry uncurry :: (a -> Prelude>: t uncurry (flip const) uncurry (flip const) :: (b, c) -> c Prelude>: t snd snd :: (a, b) - > b

Data.Tuple-modulen i standardbiblioteket definerer funksjonen swap :: (a, b) -> (b, a), som bytter ut elementene i et par:

GHCi> swap (1, "A") ("A", 1)

Denne funksjonen kan uttrykkes som:

Prelude> la swap = uncurry (snu (,)) Prelude> swap (1, "A") ("A", 1)

Strenge og slappe funksjoner

Lat evaluering fører til det faktum at det i mange situasjoner er mulig å eliminere programufullstendighet.

Const42 :: a -> Int const42 = const 42

Const42-funksjonen ignorerer fullstendig verdien av argumentet, derfor, innenfor rammen av den late beregningsmodellen, hvis du sender en kompleks beregning til den som et argument, vil denne beregningen aldri skje. Dette betyr at ethvert program, inkludert et ikke-avsluttende program, kan sendes som argument til const42.

* Demo> const42 True 42 * Demo> const42 123 42 * Demo> const42 (1 + 3) 42 * Demo> const42 undefined 42

Funksjoner som const42 kalles slappe funksjoner. Hvis en divergerende beregning sendes til en funksjon som et argument, og resultatet er en verdi som ikke er divergent, kalles en slik funksjon ikke-streng. En funksjon kalles streng slik at hvis vi sender et divergent argument til den, så er verdien av denne funksjonen nødvendigvis divergent. En funksjon med to argumenter kan være streng eller ikke-streng for det andre argumentet, avhengig av verdien av det første argumentet. Alvorlighetsanalyse er nødvendig for å gjøre et Haskell-program veldig effektivt.

Jeg tror alle vanlige lesere av bloggen min vet at jeg er en moderat ivrig følger. Det er ikke det at jeg ikke vil høre noe om alt annet – nei, det er bare det at jeg alltid tar til orde for muligheter for valg, diskusjon og konstant søk best, noe som til syvende og sist betyr for en slags utvikling av utviklingsmetodologier. Personkulten er like ubehagelig for meg som dyrkelsen av en egen programmeringsmetodikk, fordi det på lang sikt er en entydig vei til stagnasjon og galskap.

For å fortsette dette pedagogiske arbeidet, vil jeg i dag fokusere på - et fantastisk funksjonelt programmeringsspråk. Jeg har fått det samme spørsmålet tre ganger allerede: hvor skal jeg begynne (fortsette) for å lære Haskell?

Kanskje det er på tide å gi et kort svar, råd. Her generell algoritme innlegg i dette emnet fra meg.

Trinn 0 - Introduksjon. Haskell? Cho the crap?

Et velkjent paradoks blant rekrutterere av programmerere, ofte referert til som "", og det er formulert omtrent slik:

Hvis et selskap velger et mindre vanlig esoterisk programmeringsspråk som hovedprogrammeringsspråk, så har et slikt selskap størst sjanser til å få de beste programmererne på markedet. Hvorfor? Faktum er at de programmererne som det ikke er noe problem å lære nye ting for vil ønske å bli ansatt i et så "rart selskap"; de for hvem lite kjent og vanskelig å nå ikke er en hindring; og til slutt, de som har høy nok selvtillit til å tilby seg selv under slike notorisk tøffe forhold.

Og viktigst av alt, det er to typer programmerere: de som lærer å få Godt jobba og de velger alltid mainstream fordi dette øker sjansene deres for å finne jobb betydelig; og de - som bare liker å lære noe nytt, å utvikle seg, og de velger alltid den beste, som ofte er langt fra den mest lønnsomme som deres medkarrierer gjør. Så, Python-paradokset hevder at ved å starte utvikling på det avanserte eksotiske, vil du, som en støvsuger, tiltrekke deg den andre kategorien programmerere (det motsatte er sant når det kommer til selskaper som tilbyr jobber).

Jeg kan nevne som et abstrakt eksempel på en helt lik skjult målretting av fokusgrupper med gitte egenskaper, en historie fra hans siste ungdom. Da jeg fortsatt studerte, hadde vi en "rar" holdning, som demonstrativt, når vi presenterte matanalyse aldri tatt hensyn til høyre side publikum. Det vil si at det var to rader i salen – venstre og høyre – og nå holder han et foredrag, forklarer noe, men samtidig ser han ALDRI på høyre rad – all oppmerksomhet er kun til elevene fra venstre rad . Også med svarene på spørsmålene - den høyre raden fantes ikke for ham. Derfra hører han ingenting.

Som et resultat, i løpet av lang tid, la jeg merke til en interessant ting: i gruppen vår var det en automatisk selvidentifikasjon og fragmentering i de som kalkulus nødvendig og interessant (og de tok umiddelbart plass på venstre kjørefelt, etter å ha akseptert reglene for dette merkelige spillet), og de som ikke trenger det, og de skyndte seg å ta plass til høyre, for her ble de overlatt til seg selv . Denne sorteringen skjedde av seg selv, uten noen ekstraordinær innsats fra utsiden. For læreren, slik jeg forsto motivasjonen hans, var det veldig praktisk - han kastet ikke bort energien sin på i det vesentlige utenforstående, men skapte umiddelbart forutsetninger for å konsentrere sin styrke og oppmerksomhet om de som trengte kunnskapen hans. For elever på C-trinn var dette også en vinnersituasjon.

3. Scene - søk etter dybde og følelse av et nytt språk

Den tredje fasen graver allerede dypere. Her foreslår jeg å bryte de tradisjonelle mønstrene litt (og åh, hvor jeg elsker å gjøre dette) og bytte til et fundamentalt annet format for å presentere informasjon: dette diversifiserer ikke bare oppgaven med å lære et språk, men involverer også nye, hittil uaktiverte områder av hjernen din (vi vil spesielt belaste programmerings venstre hjernehalvdel). Jeg mener en utmerket videoforelesning om Haskell fra en veldig smart fyr med engelske røtter.

Her er resultatet hennes:

Kurset funksjonell programmering ved bruk av Haskell
(Språk Engelsk)
35 timer | 1280 × 720 | XviD - 1326 Kbps
25.00fps | Mp3 - 96Kbps | 20,06 GB

Du kan laste ned denne flotte videoforelesningen. Jeg råder deg til å skynde deg til de rasende rettighetshaverne kom løpende og spikret dette sjeldne arkivet av nafig ( Oppdater: ja, klarte det: amen. Jeg inviterer alle interesserte til å bruke denne megalinken).

4. Den siste fasen - praksis

Å finne den mest passende og inspirerende praktiske oppgaven for deg er temaet i et eget innlegg, hvor jeg vil gi noen levende eksempler fra kjente liv. goner-programmerere, så foreløpig vil vi utsette mine forklaringer på dette den siste fasen en stund til side.

Her, noe slikt, delvis åpenbart for mange, ville jeg gi til alle som vil lære Haskell, og ikke bare. Gå for det!

Og avslutningsvis, for tilhengere av andre programmeringsspråk:

Haskell er et hellig programmeringsspråk tildelt sjamaner Bubenland deres øverste guddom Komonada hvordan universalmiddel for kommunikasjon og åndelig rensing, egnet for både guddommelige enheter og (noen) rene dødelige som har kommet seg etter alvorlige stadier av intellektet. På grunn av sin opprinnelse har språket alltid vært funksjonelt rent. I gjennomsnitt starter læringen av Haskell ved 10-12 år. Å komme i gang i tide vil sikre at du når det tredje nivået av kraft innen 75 år. Du bør ikke utsette det du kan gjøre til neste liv i det minste begynne på denne.

Matthew Griffin

Etter å ha studert Haskell i lang tid, har jeg fått nok erfaring til å gi deg et par tips nå. Jeg vil også gjerne lære meg noen prinsipper før jeg går videre.

Og selv om jeg noen ganger tyr til Python hjelp, er det meste av arbeidet mitt på nettet nå gjort i Haskell.

Data først

Jeg tenkte på å gå fra et dynamisk språk til et statisk, og i Haskell er datastrukturen du jobber med tydelig beskrevet i erklæringen. I Python, mesteparten av tiden, gjør kode denne oppgaven.

Da jeg først så funksjoner i Haskell, lurte jeg på: «Hva er data? Tar denne funksjonen noe ved inngangen og gir noe ved utgangen?" Og da jeg jobbet med Python, hadde jeg et spørsmål: "HVA SIER KODEN?"

Haskell-datastrukturen har formet min måte å tenke på, som jeg tok med meg til arbeidet mitt i Python. Koden min er merkbart bedre. Og selv om det veldig ofte virket for meg at formen på dataene jeg beskrev endret seg uten grunn, ble faktisk alt klart med en liten studie av problemet. Begrensninger på friheten til å endre data gjør også koden mindre kompleks og lettere å forstå.

Lesbarhet av koden

Python tiltrakk meg med evnen til å skrive virkelig lesbar kode... Haskell-kodeeksemplene så bare forferdelige ut, med unntak av noen utdrag som så ut til å ha blitt plukket med vilje for ikke å skremme nybegynnere. Og selv om noen kodebiter så veldig fine ut, var det meste av kildekoden fylt med noe skummelt. Og bak dette «forferdelige» var all kraften i språket skjult.

Jeg ville definitivt ikke skrive "smart" kode - en som kan demonstrere de imponerende egenskapene til språket, men som er helt upraktisk.

Imidlertid evaluerte jeg lesbarheten til Haskell sammenlignet med andre populære programmeringsspråk. Det var som om jeg evaluerte kinesiskå være engelsk som morsmål.

Jeg innså at Haskell ikke er et «smart» språk, men et utspekulert språk. Det er absolutt mulig å skrive "smart" kode i Haskell, men dette er ikke et vanlig tilfelle. Samtidig er kraften til smartkode begrenset til sterk skriving. Hvis funksjonen skulle returnere Int, vil den returnere Int. Vel, eller kaster en kompileringsfeil som en siste utvei.

Og de kraftigere abstraksjonene i Haskell minner om en slags magi som jeg prøvde å unngå når jeg jobbet med Python.

Jeg er seriøs når det gjelder lesbarhet

Først, tro og overbevis deg selv om at, ja, folk leser oppføringer på dette nye språket for deg, og de gjør det raskt og regelmessig. Etter å ha tatt for meg de fleste kjente nyansene, begynte jeg å forholde meg rolig til koden i Haskell.

Kommentarer. De låner øverste linje i et av kapitlene i vår "bok".

Dette kapittelet beskriver hvordan Tommy gikk til butikken og kjøpte en and.

kapittel :: Tommy -> Marked -> And

Funksjoner fra en annen, redusert funksjon, i det store bildet, reduser koden til det maksimale.

Korthet. Du trenger ikke massevis av kode for å gjøre ideene dine til virkelighet.

Sett inn symboler

Jeg ville også nevne plugin-funksjonene som er vanlige på Haskell-språket. Sett inn funksjoner (eller operatorer) er de funksjonene som bruker mellom for to argumenter i stedet for før. Et enkelt eksempel er "+".

I Haskell har vi noen standard utfyllingstegn: $,<$>, <-, ->osv. De kan forvirre deg litt i begynnelsen av reisen.

Ikke bekymre deg! Når du lærer hvordan du bruker dem, vil du forstå hvor nyttige og enkle de er. Jeg telte rundt 5 symboler som jeg bruker regelmessig.

Jeg anbefaler ikke å bruke linsebiblioteket med en gang, siden det inneholder massevis av slike symboler. Dette biblioteket er veldig nyttig, men til å begynne med bør du kunne oppnå stor suksess uten det. Vent til du trygt kan skrive moderat komplekse programmer i Haskell, og begynn deretter å bruke lens.

Du må fullstendig fornye kunnskapen din

Etter hvert som du lærer Haskell, vil du komme over nye termer underveis, som f.eks funksjonær eller monad.

Du kan finne disse ordene vanskelige å huske og lære. Når du begynner å bli kjent med et populært programmeringsspråk, er mange av begrepene klare og kjente for deg fra språkene du har lært.

Vi husker informasjon ved å knytte den til annen informasjon. Jeg har for eksempel ingen assosiasjoner til ordet funksjonær, så det blir ikke lett for meg å lære dette begrepet.

Strategien min for å lære slike ord kom til meg ganske nylig, og jeg begynte å bruke den hver gang jeg så et begrep jeg ikke forsto. Den består i utvalget av synonymer for de ordene du ikke forstår og ikke er kjent med. Etter en tid lærte jeg hvordan jeg fant opp disse synonymene.

For eksempel, funksjonær.

I Haskell vises mye på skjermen din. For eksempel er en liste en funksjon. Dette betyr at en visningsfunksjon som bruker en annen funksjon vises i listen. Deretter opprettet ny liste med resultatene.

Kart (+1) - resultater i

Så jeg ga navnet til denne - mapa. Ordet mapa er veldig lett å huske. Listen er en funksjonær. Listen er et kart.

Mitt feilkontrollsystem

Da jeg skrev i Python, var feilsøkingsverktøyet mitt print statements.

I Haskell brukte jeg systematiske verktøy.

Men! Du kan bruke Debug.Trace. Denne teknikken er lik den i Python funksjon utskrift er uavhengig av Haskell IO. OG denne modulen kan være gunstig i begynnelsen. Da du først begynte å jobbe med Haskell, tenkte du på hvor mye du ville bruke det?

Hvis du ikke bruker sporsetninger i koden din etter å ha sjekket for feil, vil du umiddelbart legge merke til at koden din ser dårligere ut i Haskell enn den gjør i Python.

Beste Monad-opplæring

Hver gang du hører om suksessen til en Haskell-programmerer, lurer du på: "Hvordan lærte denne personen monader til slutten?" Så alt er i orden.

Jeg må analysere litt. Jeg visste en ting eller to om dette da jeg skrev i Python. Men på grunn av min uerfarenhet på dette området, er det nå ganske vanskelig å gjøre en analyse.

Ok, nå skal jeg fortelle deg mer. Jeg vil forklare i Haskell.

Jeg fant en YouTube-video, "Parsing Stuff in Haskell", som beskriver hvordan du gjør JSON-parsing i Haskell ved å bruke Parsec-biblioteket.

Denne videoen hjalp meg utilsiktet å finne ut hvordan jeg kunne bruke monader og applikative funksjoner til å lage det jeg trengte. Jeg fant ut hvordan funksjonene deres (har, har) er knyttet til hverandre.

Etter å ha skrevet parsing ved hjelp av videoen begynte jeg å forstå all koden. Jeg begynte også å forstå hele hans "natur". Men i den innledende fasen vil dette ikke komme til nytte.

Så Parsec gjør jobben sin ganske bra, slik at min uerfarenhet når jeg skriver analyse er praktisk talt usynlig. Akkurat som enhver annen nybegynner i Haskell, kunne jeg enkelt lage gode programmer og operasjoner selv i begynnelsen av mitt bekjentskap med dette språket.

Dra nytte av kunnskapen din

Haskell er hovedspråket mitt av flere grunner:

  1. Valget av teknologier som jeg vil bruke.
  2. Jeg kan skrive programmene mine raskere, og mesteparten av tiden selger jeg disse programmene.
  3. Du trenger ikke å forholde deg til små feil.
  4. Selv når jeg står overfor flere feil, løser jeg dem raskt, siden de er mer eller mindre klare.
  5. Python fokuserte ikke på hastighet. Haskell gjør det samme, men valget er mitt.
  6. Refaktorering er faktisk ganske vindfull. I Python skjeller jeg av og til mye på meg selv når jeg glemte å fikse små feil i koden, noe som senere skapte store vanskeligheter.
  7. Flotte biblioteker. Hovedtrekket til Haskell er høy kvalitet biblioteker.
  8. Fellesskapet er klare til å hjelpe.
  9. Enkelt å skalere kode til ønsket kjerne.
  10. Haskell oppdateres ofte. I fjor, da GHC (kompilatoren for Haskell) ble oppdatert til versjon 7.8, noe som gjorde koding dobbelt så enkelt, ble mange webservere fremskyndet.

Til slutt vil jeg si at Haskell har gitt meg mye moro. Det var beste opplevelsen i hele mitt liv.

Jeg har blitt spurt dem mange ganger. Jeg svarer.

"Hva er denne Haskell av deg?"

Haskell er et rent funksjonelt programmeringsspråk generelt formål, kan brukes til å løse et bredt spekter av problemer. Kompilert, men det kan også oppføre seg som et skript. Kryssplattform. Lat, sterkt statisk skrevet. Og det er ikke som andre språk. I det hele tatt.

"Er dette et nytt språk?"

Ikke i det hele tatt. Historien til Haskell går tilbake til 1987. Dette språket ble født i matematiske sirkler da en gruppe mennesker bestemte seg for å lage det beste funksjonelle programmeringsspråket. I 1990 ble den første versjonen av språket utgitt, oppkalt etter den kjente amerikanske matematikeren Haskell Curry. I 1998 ble språket standardisert, og fra 2000-tallet begynte det sakte å komme inn i verden. praktisk programmering... Gjennom årene har språket blitt bedre, og i 2010 så verden sin oppdaterte standard. Vi har altså å gjøre med et språk som er eldre enn Java.

"Og hvem har laget det?"

Haskell ble skapt av mange mennesker. Den mest kjente implementeringen av språket ble nedfelt i GHC (The Glasgow Haskell Compiler), som ble født i 1989 ved University of Glasgow. Kompilatoren hadde flere hovedutviklere, hvorav to er de mest kjente, Simon Peyton Jones og Simon Marlow. Deretter ble et betydelig bidrag til utviklingen av GHC gitt av flere hundre flere mennesker. Kilde GHC-kompilatoren er åpen. Selve kompilatoren er forresten 82% skrevet i Haskell.

For de nysgjerrige: for en omfattende beretning om historien til Haskell og GHC, les.

"Finnes det biblioteker for Haskell?"

Å ja! Det er ikke engang hundrevis av dem - det er tusenvis av dem. Når du leser, vil du bli kjent med mange av dem.

"Og hva, det er allerede mulig i produksjon?"

Den er allerede i produksjon. Siden utgivelsen av den første standarden har språket blitt bedre, økosystemet har utviklet seg, nye biblioteker har dukket opp og bøker har blitt publisert. Haskell er helt klar for alvor kommersielt bruk, som det fremgår av historiene om vellykket implementering av Haskell i næringslivet, inkludert store.

"Er terskelen for å komme inn på Haskell høy?"

Ja og nei. Å mestre Haskell er vanskelig, først og fremst på grunn av dets ulikhet med andre språk, så folk med erfaring med andre språk må bryte hjernen. For å bryte dem, ikke bare for å flytte dem: Haskell får deg til å se annerledes selv på kjente ting. På den annen side er Haskell enklere enn mange kjente språk. Ikke ta mitt ord for det, du vil snart se selv. Og vet: mange mennesker, etter å ha lært smaken av Haskell, ønsker kategorisk ikke å gå tilbake til andre språk. Jeg advarte deg.

"Og jeg har også hørt om noen monader ..."

Ja, det er noe slikt. Noen ting fra Haskells verden har ingen direkte motstykker i andre programmeringsspråk, og dette forvirrer nybegynnere. Men ikke bekymre deg: Jeg selv gikk gjennom denne stuporen og forstår deg godt. Husk: det nye virker bare skummelt.

"Og hvis du sammenligner det med C ++ / Python / Scala ..."

Å sammenligne Haskell med andre språk er utenfor rammen av denne boken. Flere ganger vil du komme over kodebiter på andre språk her, men jeg presenterer dem utelukkende for å understreke forskjellen fra Haskell, og slett ikke for sammenligning i sammenheng med "bedre/verre". Og generelt vil jeg prøve mitt beste for ikke å rose Haskell for mye, jeg vil bare fortelle deg sannheten om det. Jeg har allerede gjort min konklusjon om dette språket, og du må gjøre din egen konklusjon om det.

    Typer

    Haskell-programmer er uttrykk som evalueres til verdier. Hver verdi har en type. Intuitivt kan en type forstås enkelt som et sett akseptable verdier uttrykkene. For å finne ut typen til et eller annet uttrykk, kan du bruke tolkkommandoen: type (eller: t). Alternativt kan du gi kommandoen: set + t for å få tolken til automatisk å skrive ut typen for hvert beregnede resultat.
    Hovedtypene av Haskell-språket er:
    Heltalls- og Int-typene brukes til å representere heltall og verdiene av typen heltall ikke begrenset i lengde.
    Flytetyper og Dobbel brukes til å representere reelle tall.
    Bool-typen inneholder to verdier, True og False, og er ment å representere resultatet av boolske uttrykk.
    Char-typen brukes til å representere tegn. Haskell-typenavn starter alltid med stor bokstav.
    Haskell-språket er et sterkt skrevet programmeringsspråk. Imidlertid er programmereren i de fleste tilfeller ikke pålagt å oppgi hvilke typer variablene de legger inn. Tolken selv er i stand til å utlede hvilke typer variabler brukeren bruker.
    Imidlertid, hvis det for et eller annet formål er nødvendig å erklære at en verdi tilhører en bestemt type, brukes en konstruksjon av formen: variabel :: Type. Hvis tolkealternativet + t er aktivert, skriver den ut verdiene i samme format.
    Nedenfor er et eksempel på sesjonsprotokollen for arbeid med tolken. Teksten etter Prelude>-ledeteksten forventes å bli skrevet inn av brukeren, og følgende tekst er systemets svar.

    Preludium>: sett + t
    Preludium> 1
    1 :: Heltall
    Preludium> 1.2
    1.2 :: Dobbelt
    Preludium> 'a'
    'A' :: Char
    Preludium> Sant
    Sant :: Bool

    Fra av denne protokollen vi kan konkludere med at verdier av typen Integer, Double og Char er satt i henhold til de samme reglene som i C-språket.
    Et velutviklet typesystem og sterk skriving gjør Haskell-programmer typesikre. Det er garantert at i riktig program alle typer brukes riktig i Haskell. Rent praktisk betyr dette at et Haskell-program ikke kan forårsake et tilgangsbrudd når det kjøres. Det er også garantert at uinitialiserte variabler ikke kan brukes i programmet. Dermed spores mange feil i et program ved kompilering, ikke kjøring.

    Aritmetikk

    Hugs-tolken kan brukes til å evaluere aritmetiske uttrykk. I dette tilfellet kan du bruke operatorene +, -, *, / (addisjon, subtraksjon, multiplikasjon og divisjon) med de vanlige prioritetsreglene.
    Alternativt kan du bruke operatoren ^ (eksponentiering). Dermed kan økten se slik ut:

    Preludium> 2 * 2
    4 :: Heltall
    Preludium> 4 * 5 + 1
    21 :: Heltall
    Preludium> 2 ^ 3
    8 :: Heltall
    Alternativt kan du bruke standarden matematiske funksjoner sqrt ( Kvadratrot), sin, cos, exp, etc. I motsetning til mange andre programmeringsspråk, trenger ikke Haskell å sette argumentet i parentes når du kaller en funksjon. Så man kan bare skrive sqrt 2 og ikke sqrt (2). Eksempel:

    Preludium> sqrt 2
    1,4142135623731 :: Dobbel
    Preludium> 1 + sqrt 2
    2.4142135623731 :: Dobbel
    Preludium> sqrt 2 + 1
    2.4142135623731 :: Dobbel
    Prelude> sqrt (2 + 1)
    1,73205080756888 :: Dobbel

    Fra dette eksemplet vi kan konkludere med at funksjonskallet har høyere prioritet enn aritmetiske operasjoner så uttrykket sqrt 2 + 1 tolkes som (sqrt 2) + 1 og ikke sqrt (2 + 1). Bruk parenteser for å spesifisere den nøyaktige rekkefølgen for evaluering, som i det siste eksemplet. (Egentlig har et funksjonskall forrang over en hvilken som helst binær operator.)
    Det bør også bemerkes at, i motsetning til de fleste andre programmeringsspråk, blir heltallsuttrykk i Haskell evaluert med et ubegrenset antall sifre (Prøv å evaluere uttrykket 2 ^ 5000.) I motsetning til C, hvor den maksimalt mulige verdien av typen int er begrenset av kapasiteten til maskinen (på moderne personlige datamaskiner det er 231-1 = 2147483647), kan Haskell Integer-typen lagre heltall av vilkårlig lengde.

    Tuples
    I tillegg til de enkle typene som er oppført ovenfor, kan du definere verdier i Haskell kompositttyper... For å definere et punkt på et plan, trenger du for eksempel to tall som tilsvarer dets koordinater. I Haskell kan et par spesifiseres ved å liste komponentene, atskilt med kommaer og omslutte dem i parentes: (5,3). Komponentene i et par trenger ikke å være av samme type: du kan lage et par, hvor det første elementet er en streng, det andre er et tall, og så videre.
    Generelt, hvis a og b er noen vilkårlige typer i Haskell er typen av et par der det første elementet er av type a og det andre er av type b betegnet som (a, b). For eksempel er paret (5,3) av typen (heltall, heltall); par (1, 'a') er av typen (heltall, Char). Du kan ta med flere komplekst eksempel: paret ((1, 'a'), 1.2) er av typen ((Heltall, Char), Double). Sjekk det ut med en tolk. Det skal bemerkes at selv om konstruksjoner som (1,2) og (heltall, heltall) ser like ut, betegner de i Haskell helt forskjellige enheter. Førstnevnte er en verdi, mens sistnevnte er en type. For å jobbe med par på Haskell-språket, finnes det standard funksjoner fst og snd, som returnerer henholdsvis første og andre element i paret (navnene på disse funksjonene stammer fra de engelske ordene "first" og "second"). Så de kan brukes slik

    Prelude> fst (5, True)
    5 :: Heltall
    Prelude> snd (5, True)
    Sant :: Bool
    I tillegg til par kan trippel, firedobling osv. defineres på samme måte. Deres typer er skrevet på en lignende måte.
    Preludium> (1,2,3)
    (1,2,3) :: (heltall, heltall, heltall)
    Preludium> (1,2,3,4)
    (1,2,3,4) :: (heltall, heltall, heltall, heltall)
    Denne datastrukturen kalles en tuppel. En tuppel kan lagre en fast mengde heterogene data. Fst- og snd-funksjonene er kun definert for par og fungerer ikke for andre tupler. Prøver du å bruke dem for eksempel til trillinger, gir tolken en feilmelding. Et element i en tuppel kan være en verdi av hvilken som helst type, inkludert en annen tuppel. En kombinasjon av fst- og snd-funksjonene kan brukes for å få tilgang til elementene i sammenkoblede tupler. Følgende eksempel demonstrerer å trekke ut et element 'a' fra en tuppel
    (1, ('a', 23.12)):
    Prelude> fst (snd (1, ('a', 23.12)))
    'A' :: Heltall

    Lister
    I motsetning til tupler kan en liste lagre et vilkårlig antall elementer. For å definere en liste i Haskell, må du firkantede parenteser liste opp elementene, atskilt med komma. Alle disse elementene må være av samme type. Listetype med elementer, tilhørende type a er betegnet som [a].

    Preludium>
    ::
    Preludium> ['1', '2', '3']
    [’1’,’2’,’3’] ::
    Det kan hende det ikke er noen elementer i listen. En tom liste er merket som.
    Operator: (kolon) brukes til å legge til et element i begynnelsen av en liste. Dets venstre argument må være et element, og dets høyre argument må være en liste:
    Preludium> 1:
    ::
    Prelude> '5': ['1', '2', '3', '4', '5']
    [’5’,’1’,’2’,’3’,’4’,’5’] ::
    Preludium> False:
    ::
    Enhver liste kan bygges ved å bruke (:)-operatoren og en tom liste:
    Preludium> 1: (2: (3 :))
    :: Heltall
    Operatoren (:) er høyre assosiativ, så du kan utelate parentesene i uttrykket ovenfor:
    Preludium> 1: 2: 3:
    :: Heltall
    Elementene i listen kan være en hvilken som helst verdi - tall, symboler, tupler, andre lister, etc.
    Preludium> [(1, 'a'), (2, 'b')]
    [(1, 'a'), (2, 'b')] :: [(heltall, Char)]
    Preludium> [,]
    [,] :: []
    Å jobbe med lister i Haskell, det er et stort nummer av funksjoner. I dette laboratoriearbeid vi vil bare vurdere noen få av dem.
    Hodefunksjonen returnerer det første elementet i listen.
    Halefunksjonen returnerer en liste uten det første elementet.
    Lengdefunksjonen returnerer lengden på listen.
    Hode- og halefunksjonene er definert for ikke-tomme lister. Når du prøver å bruke dem til tom liste tolken melder feil. Eksempler på arbeid med spesifiserte funksjoner:
    Preludium> hode
    1 :: Heltall
    Preludium> hale
    ::
    Preludium> hale
    :: Heltall
    Preludium> lengde
    3 :: Int
    Merk at resultatet av lengdefunksjonen tilhører Int type i stedet for heltall.
    Haskell definerer ++-operatoren for å slå sammen (sammenkjede) lister.
    Preludium> ++
    :: Heltall

    Strenger
    Strengeverdier i Haskell, så vel som i C, er spesifisert i doble anførselstegn... De er av typen String.
    Preludium> "hei" "hei" :: String
    Strenger er faktisk lister over tegn; dermed uttrykkene "hei", ["h", "e", "l", "l", "o"] og

    'H': 'e': 'l': 'l': 'o': betyr det samme, og String er et synonym for. Alle funksjoner for arbeid med lister kan brukes når du arbeider med strenger:
    Preludium> hodet "hei"
    'H' :: Char
    Preludium> hale "hei"
    "Hallo" ::
    Preludium> lengde "hei"
    5 :: Int
    Preludium> "hei" ++ ", verden"
    "Hei Verden" ::
    Å konvertere numeriske verdier til linjer og omvendt, det er lese- og visefunksjoner:
    Preludium> show 1
    "1" ::
    Prelude> "Formel" ++ show 1
    "Formel 1" ::
    Preludium> 1 + les "12"
    13 :: Heltall
    Hvis show-funksjonen ikke kan konvertere strengen til et tall, vil den rapportere en feil.

    Funksjoner
    Så langt har vi brukt de innebygde funksjonene til Haskell-språket. Nå er det på tide å lære å definere egne funksjoner... For å gjøre dette må vi studere noen flere tolkekommandoer (husk at disse kommandoene kan forkortes til én bokstav):
    Kommandoen: load laster Haskell-programmet i den angitte filen inn i tolken.
    Kommandoen: edit starter redigeringsprosessen for den sist opplastede filen.
    Kommandoen: reload leser den sist innlastede filen på nytt. Definisjoner tilpassede funksjoner må være i filen for å lastes inn i Hugs-tolken ved å bruke kommandoen: load.
    For å redigere det innlastede programmet kan du bruke kommandoen: edit. Den starter en ekstern editor (notisblokk som standard) for å redigere filen. Etter endt redigeringsøkt må redaktøren lukkes; Hugs-tolken vil lese innholdet i den endrede filen på nytt. Filen kan imidlertid redigeres direkte fra Windows-skallet. I dette tilfellet, for at tolken skal kunne lese filen på nytt, er det nødvendig å eksplisitt kalle kommandoen: reload.
    La oss se på et eksempel. Lag lab1.hs-fil i en eller annen katalog. La være full vei til denne filen - c: \ labs \ lab1.hs (dette er bare et eksempel, filene dine kan ha et annet navn). Kjør følgende kommandoer i Hugs-tolken:

    Prelude>: last inn "c: \\ labs \\ lab1.hs"
    Hvis nedlastingen er vellykket, endres tolkemeldingen til Main>. Faktum er at hvis modulnavnet ikke er spesifisert, anses det å være lik Main.
    Hoved>: rediger
    Et redigeringsvindu skal åpnes her, der du kan skrive inn teksten til programmet. Tast inn:
    x =
    Lagre filen og lukk redigeringsprogrammet. Hugs-tolken vil laste inn filen
    c: \ labs \ lab1.hs og nå vil verdien av variabelen x bli bestemt:
    Hoved> x
    ::
    Merk at \-tegnene dupliseres når du skriver filnavnet i: load kommando-argumentet. Som i C-språket, fungerer \-tegnet i Haskell som en indikator på begynnelsen av et tjenestetegn ('\ n', etc.) For å skrive inn \-tegnet direkte, må du, som i C, escape det med en annen \ ...
    Nå kan du gå videre til å definere funksjoner. Opprett, i samsvar med prosessen beskrevet ovenfor, en fil og skriv følgende tekst inn i den:

    kvadrat :: Heltall -> Heltall
    kvadrat x = x * x

    Den første linjen (kvadrat :: Heltall -> Heltall) erklærer at vi definerer et funksjonskvadrat som tar en heltallsparameter og returnerer et heltallsresultat. Den andre linjen (kvadrat x = x * x) er selve funksjonsdefinisjonen. Kvadratfunksjonen tar ett argument og returnerer kvadratet. Funksjoner i Haskell er "førsteklasses" verdier. Dette betyr at de er "lik" med verdier som heltall og reelle tall, tegn, strenger, lister osv. Funksjoner kan sendes som argumenter til andre funksjoner, returneres fra funksjoner osv. Som alle verdier i Haskell, er funksjoner av en type. Typen av en funksjon som tar verdier av type a og returnerer verdier av type b er betegnet som a-> b.
    Last den genererte filen inn i en tolk og kjør følgende kommandoer:

    Hoved>: type firkant
    kvadrat :: Heltall -> Heltall
    Hoved> kvadrat 2
    4 :: Heltall
    Merk at typedeklarasjonen av kvadratfunksjonen i prinsippet ikke var nødvendig: tolken selv kunne utlede nødvendig informasjon om typen av funksjonen fra dens definisjon. For det første vil imidlertid den antydede typen være mer generell enn Integer -> Heltall, og for det andre, å eksplisitt indikere typen funksjon er "god praksis" ved programmering i Haskell, siden typedeklarasjonen fungerer som en slags dokumentasjon for funksjonen og hjelper med å identifisere programmeringsfeil.
    Brukerdefinerte funksjoner og variabelnavn må begynne med en liten latinsk bokstav. Resten av tegnene i navnet kan være store eller små med latinske bokstaver, tall eller symboler _ og '(understrek og apostrof). Følgende er derfor eksempler på gyldige variabelnavn:

    var
    var1
    variabelnavn
    variabelnavn
    var '

    Betingede uttrykk

    Du kan bruke betingede uttrykk i en funksjonsdefinisjon i Haskell. La oss skrive signumfunksjonen som beregner tegnet til argumentet som sendes til den:

    signum :: Heltall -> Heltall
    signum x = hvis x> 0 så 1
    annet hvis x annet 0

    Det betingede uttrykket er skrevet som:
    hvis tilstand deretter uttrykk annet uttrykk. Merk at selv om dette uttrykket ser ut som den tilsvarende operatoren i C eller Pascal, må et betinget uttrykk i Haskell ha både den daværende delen og den andre delen. Uttrykk i da-del og annet-del betinget operatør må være av samme type. En betingelse i en betinget setningsdefinisjon er ethvert uttrykk av typen Bool. Sammenligninger er eksempler på slike uttrykk. Følgende operatører kan brukes til sammenligning:
    , = - disse operatorene har samme betydning som i C-språket (mindre enn, større enn, mindre enn eller lik, større enn eller lik).
    == er en likhetsoperatør.
    / = - operatør for å sjekke for ulikhet.
    Uttrykk som Bool kan kombineres med vanlig logiske operatorer&& og || (AND og OR), og negasjonen fungerer ikke.
    Eksempler på gyldige betingelser:
    x> = 0 && x x> 3 && x / = 10
    (x> 10 || x Selvfølgelig kan du definere dine egne funksjoner som returnerer Bool-verdier og bruke dem som betingelser. Du kan for eksempel definere funksjonen isPositive, som returnerer True hvis argumentet er ikke-negativt og False ellers:
    isPositive :: Heltall -> Bool
    isPositive x = hvis x> 0 så Sant ellers usant

    Tegnfunksjonen kan nå defineres som følger:
    signum :: Heltall -> Heltall
    signum x = hvis er positiv x så 1
    annet hvis x annet 0
    Merk at isPositive-funksjonen kan defineres på en enklere måte:
    er positiv x = x> 0

    Informasjonen er hentet fra: http://sguprog.narod.ru/