I boken "The Pragmatic Programmer" (hvis du ikke har lest den, bør du slutte å lese denne artikkelen og gjøre det nå!) står det at vi hvert år bør lære oss ett nytt programmeringsspråk.
Selv om noen kanskje vil hevde at det er for mye arbeid, kan vi alle være enige om at det kan være en god idé. Det er ikke så lett å velge et nytt språk å lære seg. Vi ønsker vel ikke å bruke tid på noe som vi kanskje aldri kommer til å bruke i praksis? Men kanskje vi noen ganger bør gjøre et unntak og lære oss noe bare for moro skyld? Jeg vil gjerne presentere Brainfuck-språket. Det er et språk du kan lære på et par minutter, så det er ikke noe problem å investere for mye av tiden din forgjeves. Jeg kan også love at det å løse et hvilket som helst problem med Brainfuck vil stimulere hjernen din (alle f*cks er bare en bonus ;)). La oss komme i gang!ifølge Wikipedia:
Brainfuck er en esoterisk programmeringsspråk opprettet i 1993 av Urban Müller. Språket består av bare åtte enkle kommandoer og en instruksjonspeker. Selv om det er fullstendig Turing-komplett, er det ikke ment for praktisk bruk, men for å utfordre og underholde programmerere.
Oversikt over språk
Forestill deg et uendelig langt bånd (eller tape) som består av celler, hver og en initialisert til 0. Det finnes også en bevegelig datapeker som i utgangspunktet peker til den første cellen. Det finnes også to strømmer av bytes for inndata og utdata. Instruksjonene utføres sekvensielt, én etter én. Maskinen stopper etter å ha utført den siste.
Kommando
Hva gjør den?
>
flytte datapekeren til neste celle til høyre
<
flytte datapekeren til neste celle til venstre
+
øke verdien av gjeldende celle
–
redusere verdien av gjeldende celle
.
skriver ut byten til en aktuell pekt celle i ASCII kode
,
leser én byte fra stdin og lagrer verdien i den aktuelle cellen
[
hvis den gjeldende cellen er 0, hopper du til den matchende ]
]
hopp til matchende [
Alle andre tegn enn ><+-.,[] ignoreres.
La oss se på et enkelt eksempel:
,+.
Det vil bli tolket på følgende måte:
leser én byte og lagrer den i gjeldende celle (cell0)
øke verdien av gjeldende celle (cell0 = cell0 + 1)
skrive innholdet i gjeldende celle til utdata
Resultatet er at ett tegn leses fra inndataene, og det neste tegnet fra ASCII-tabellen skrives ut.
Tolker / kompilator
Før vi skriver noen nyttige (?) programmer i Brainfuck, trenger vi en tolk eller en kompilator. AFAIK, det finnes ingen offisiell, men det er ikke noe problem. Det finnes dusinvis av uoffisielle på Internett. Jeg kan anbefale disse to:
"Hello World!" bør være det første programmet vi skriver når vi lærer et nytt språk. Men det er litt vanskeligere å skrive det i Brainfuck enn i andre språk. Vi må begynne med noe enklere... La oss skrive et program som skriver ut en enkelt bokstav "H" på skjermen (så spennende :D):
Hvordan fungerer det? Den setter verdien av gjeldende celle til 72 (utfører 72 trinn) og skriver den ut på skjermen ved hjelp av "." (H har koden 72 i ASCII). Nå vet du hva vi skal gjøre for å skrive ut "Hello World!" på skjermen, men før vi gjør det, skal vi gjøre en liten refaktorisering. Å skrive alle disse '+' krever for mye skriving og telling. Vi kan gjøre det kortere ved å bruke [ og ] for looping. For å sette verdien til 72 kan vi f. eks. lage en løkke som øker verdien 7 ganger med 10. På denne måten får vi 70. Ved å legge til 2 blir det 72. Det ser slik ut:
++++++++++ # sett cell0 til 10
[ # loop til cell0 er 0
- # reduser cell0
> # flytt datapekeren til høyre (celle1)
+++++++ # øker celle1 med 7
# flytt datapekeren til høyre (cell1)
++ # øker med 2
. # skriver ut resultatet
Jeg har tatt med kommentarer for å gjøre det tydelig hvordan alt fungerer. Det samme programmet uten kommentarer:
++++++++++[->+++++++++.
Er det ikke vakkert?
Hallo verden!
Hvis vi går tilbake til "Hello World!"-programmet vårt. Vi kan sette verdien av den første cellen til 72 (H) og skrive den ut, sette verdien av den andre cellen til 101 (e) og skrive den ut, sette verdien av den tredje cellen til 108 og skrive den ut, og så videre. Her er implementeringen av denne algoritmen:
Ja, bare 1120 byte for å skrive ut "Hello World!" ... Men vi kan gjøre det bedre! I stedet for å bruke en ny celle for hvert tegn, la oss bruke bare én. For å skrive ut bokstaven "e" (101) kan vi gjenbruke verdien i celle0 (72). Vi kan øke den med én 29 ganger (101 - 72). Og resultatet blir som følger:
Det er bare 106 byte, og den skriver ut en ny linje på slutten! Fantastisk.
Reversering av en streng
Nå er vi klare til å skrive noe mer utfordrende. La oss skrive et program som leser en linje fra inndata og skriver den ut i omvendt rekkefølge. Det første problemet er å lese tegn og stoppe på det nye linjetegnet. Husk at det ikke finnes noen pause, hvis eller andre lignende uttalelser. Vi er nødt til å bruke [ og ]. La oss starte med et program som leser alle tegn fra inndata og plasserer dem i påfølgende celler:
,[>,]
Den starter med å lese første tegn og fortsetter til siste , operasjonen returnerer 0. Den vil imidlertid løpe i en evig løkke i en implementering som returnerer noe annet enn O for EOF (språket spesifiserer ikke denne oppførselen). Så hvordan kan vi stoppe på det nye linjetegnet? Her er trikset:
+[++++++++++>,----------]
Vi starter med celle0 satt til 1 for å sikre at løkken vår kjøres minst én gang. I en løkke øker vi verdien av den aktuelle cellen med 10, flytter datapekeren til neste celle, leser ett tegn og reduserer verdien med 10. På denne måten, hvis det leses et nytt linjetegn (10 i ASCII), vil programmet stoppe i neste iterasjon, ellers vil verdien bli gjenopprettet ved å legge til 10.
Etter dette trinnet vil cellene våre se slik ut:
11 C1 C2 C3 0* 0 0 0
Cn er det n-te tegnet fra inndata, og * er den nåværende datapekerens posisjon. Nå må vi begynne å flytte datapekeren til venstre, og skrive ut alle cellene til vi når verdi 11. Her er mitt syn på oppgaven:
Jeg oppfordrer deg til å analysere det på egen hånd :-).
Sammendrag
Da jeg snublet over Brainfuck, et esoterisk programmeringsspråk, avfeide jeg det først som en gimmick eller en spøk. Dette særegne, og som mange kanskje vil hevde, ufattelig vanskelige språket, fremsto for meg som noe som kun var ment for underholdning. Men med tiden endret min oppfatning av Brainfuck seg ganske dramatisk.
Brainfucks gåtefulle natur utfordrer deg, og presser deg til å utvide perspektivet ditt på programmeringsspråk. Dette esoteriske språket lar deg sette pris på skjønnheten og nødvendigheten av høynivåspråk som vi er vant til. Det setter fokus på betydningen av abstraksjoner, riktige navnekonvensjoner og et organisert minneoppsett i programmeringsspråkene. Dette er noe Brainfuck, med sitt minimalistiske design bestående av bare åtte enkle kommandoer, ikke tilbyr.
Brainfuck er et Turing-komplett språk som ytterligere understreker viktigheten av å ha en klar og sammenhengende kildekode. Til tross for at det er anerkjent som et av de mest utfordrende esoteriske språkene å skrive programmer i, skinner det ironisk nok som en nybegynnerfavoritt for alle som ønsker å lage en egen Brainfuck-kompilator eller Brainfuck-tolk. Årsaken er enkelheten i kommandosettet, og det faktum at det ikke krever kompleks parsing.
Å lage et Brainfuck-program er unikt på to måter. For det første må du venne deg til å bruke en enkelt minnepeker, noe som tvinger deg til å tenke annerledes om kildekoden din. For det andre har du "null-alternativet", som er muligheten til å nullstille minnecellen til null, en funksjon som ikke er vanlig i andre formelle programmeringsspråk.
Når det gjelder læring, er det mer enn man tror når det gjelder Brainfuck. Med nok tid og den rette innstillingen er det mulig å skrive det samme programmet på mange forskjellige måter ved hjelp av ulike Brainfuck-koder. Den siste halvdelen av denne reisen handler om å være oppfinnsom og finne nye, kreative måter å bruke de seks symbolene på.
Selv om Brainfuck-tolkene er minimalistiske, gir de deg en dyp forståelse av hvordan koden kjører, hva programmet skriver ut og den underliggende mekanikken i et Turing-komplett språk. Brainfuck er ikke bare nok et esoterisk programmeringsspråk. Det er en helt ny dimensjon, et nytt syn på hvordan vi ser, forstår og skriver programmer.