Raamat "The Pragmatic Programmer" (kui te pole seda lugenud, lõpetage selle artikli lugemine ja tehke seda kohe!) ütleb, et igal aastal peaksime õppima ühe uue programmeerimiskeele.
Kuigi mõned võivad väita, et see on liiga suur pingutus, võiksime kõik nõustuda, et see võib olla hea mõte. Uue keele valimine õppimiseks ei olegi nii lihtne. Me ei taha ju pühendada oma aega millelegi, mida me võib-olla kunagi praktikas ei kasuta, või? Aga võib-olla peaksime mõnikord tegema erandi ja õppima midagi lihtsalt lõbu pärast? Ma tahaksin teile tutvustada Brainfuck keelt. See on keel, mida saab õppida paari minutiga, nii et ei ole probleemi, et investeerida liiga palju oma aega asjata. Samuti võin ma lubada, et mis tahes probleemi lahendamine Brainfuckiga stimuleerib teie aju (kõik f*kad on lihtsalt boonus ;)). Alustame!Wikipedia järgi:
Brainfuck on esoteeriline programmeerimiskeel loodud 1993. aastal Urban Mülleri poolt. Keel koosneb ainult kaheksast lihtsast käsust ja käsu näitajast. Kuigi see on täielikult Turingi täisväärtuslik, ei ole see mõeldud praktiliseks kasutamiseks, vaid programmeerijate väljakutseks ja lõbustamiseks.
Keele ülevaade
Kujutage ette lõpmata pikk lint (või lint), mis koosneb lahtritest, millest igaüks on initsialiseeritud 0. Samuti on olemas liikuv andmetähis, mis algselt osutab esimesele lahtrile. Samuti on kaks baitide voogu sisendiks ja väljundiks. Käskude täitmine toimub järjestikku, ükshaaval. Masin peatub pärast viimase käsu täitmist.
Käsk
Mida see teeb?
>
liigutada andmete osuti järgmisesse lahtrisse paremal pool.
<
liigutada andmete osuti järgmisesse lahtrisse vasakul asuvasse lahtrisse
+
praeguse lahtri väärtuse suurendamine
–
praeguse lahtri väärtuse vähendamine
.
väljastada antud hetkel osundatud lahtri bait ASCII-vormingus kood
,
loeb ühe baidi stdinist ja salvestab selle väärtuse praegusesse lahtrisse
[
kui praegune lahter on 0, siis hüpatakse vastavasse lahtrisse ]
]
hüpata sobiva [
Kõik tähemärgid peale ><+-.,[] ignoreeritakse.
Vaatame lihtsat näidet:
,+.
Seda tõlgendatakse järgmiselt:
loe üks bait ja salvesta see praegusesse lahtrisse (cell0)
praeguse lahtri väärtuse suurendamine (cell0 = cell0 + 1)
kirjutab praeguse lahtri sisu väljundisse
Selle tulemusena loetakse sisendist üks märk ja trükitakse järgmine märk ASCII tabelist.
Tõlkija / kompilaator
Enne kui me kirjutame Brainfuckis kasulikke (?) programme, vajame interpretaatorit või kompilaatorit. AFAIK ei ole ametlikku sellist olemas, aga see ei ole probleem. Mitteametlikke on internetis kümneid. Võin soovitada neid kahte:
"Hello World!" peaks olema esimene programm, mida me uue keele õppimise ajal kirjutame. Kuid selle kirjutamine Brainfuckis on veidi raskem kui teistes keeltes. Peame alustama millestki lihtsamast... Kirjutame programmi, mis trükib ekraanile ühe tähe "H" (nii põnev :D):
Kuidas see toimib? See seab praeguse lahtri väärtuse 72-le (72 sammu) ja trükib selle ekraanile, kasutades "." (H on ASCII-koodiga 72). Nüüd te teate, mida me peaksime tegema, et printida ekraanile "Hello World!", kuid enne seda teeme väikese refaktooringu. Kõigi nende "+" kirjutamine nõuab liiga palju trükkimist ja lugemist. Me saame selle lühemaks teha, kui kasutame [ ja ] loopingu jaoks. Väärtuse 72 määramiseks võime näiteks teha tsükli, mis suurendab väärtust 7 korda 10 võrra. Nii saame 70. Lisades 2, saame tulemuseks 72. See näeb välja nii:
++++++++++ # seadistage cell0 väärtuseks 10.
[ # loop kuni cell0 on 0
- # vähendada cell0
> # liiguta andmetähis paremale (lahter1)
+++++++ # suurendada lahtrit1 7 võrra
# liiguta andmetähis paremale (lahter1)
++ # suurendada 2 võrra
. # trükkida tulemus
Olen lisanud kommentaarid, et teha selgeks, kuidas kõik toimib. Sama programm ilma kommentaarideta:
++++++++++[->+++++++++.
Kas see pole mitte ilus? 🙂 .
Tere maailm!
Tulles tagasi meie programmi "Hello World!" juurde. Võime määrata esimese lahtri väärtuseks 72 (H) ja printida selle, määrata teise lahtri väärtuseks 101 (e) ja printida selle, määrata kolmanda lahtri väärtuseks 108 ja printida selle jne. Siin on selle algoritmi rakendamine:
Jah, ainult 1120 baiti, et printida "Hello World!"... Aga me saame paremini! Selle asemel, et kasutada iga tähemärgi jaoks uut lahtrit, kasutame vaid ühte. Tähe "e" (101) trükkimiseks saame uuesti kasutada lahtris0 (72) olevat väärtust. Me saame seda suurendada ühe võrra 29 korda (101 - 72). Ja tulemus on järgmine:
See on ainult 106 baiti ja see trükib uue rea lõppu! Hämmastav.
Stringi ümberpööramine
Nüüd oleme valmis kirjutama midagi keerulisemat. Kirjutame programmi, mis loeb sisendist rea ja trükib selle tagurpidi. Esimene probleem on lugeda tähemärke ja lõpetada uue rea tähemärgi juures. Pidage meeles, et ei ole break, kui või muud sarnased avaldused. Me peame kasutama [ ja ]. Alustame programmiga, mis loeb sisendist kõik tähemärgid ja paigutab need järjestikesse lahtritesse:
,[>,]
See algab esimese tähemärgi lugemisega ja jätkub kuni viimase tähemärgini. , operatsiooni tagastamine 0. Siiski, see loopib igavesti rakenduses, mis tagastab midagi muud kui O . EOF (keel ei täpsusta seda käitumist). Kuidas saame siis lõpetada uue rea märgil? Siin on trikk:
+[++++++++++>,----------]
Alustame lahtri0 väärtusega 1, et tagada, et meie tsükkel täidetakse vähemalt üks kord. Loopis suurendame praeguse lahtri väärtust 10 võrra, liigutame andmetähise järgmisesse lahtrisse, loeme ühe tähemärgi ja vähendame selle väärtust 10 võrra. Sel viisil, kui on loetud uus rea märk (10 ASCII-s), peatub programm järgmisel iteratsioonil, vastasel juhul taastatakse selle väärtus, lisades 10.
Pärast seda sammu näevad meie rakud välja nii:
11 C1 C2 C3 C3 0* 0 0 0
Cn on n-nes märk sisendist ja * on praegune andmete osuti positsioon. Nüüd peame alustama andmete osuti vasakule liigutamist ja printima kõik lahtrid, kuni jõuame väärtuseni 11. Siin on minu nägemus ülesandest:
Kui ma sattusin Brainfucki, esoteerilise programmeerimiskeele peale, jätsin selle esialgu kõrvale kui midagi muud kui trikk või nali. See omapärane ja, nagu paljud võivad väita, meeletult raske keel tundus mulle kui midagi, mis on mõeldud ainult meelelahutuseks. Kuid aja jooksul muutus minu suhtumine Brainfucki üsna dramaatiliselt.
Brainfucki mõistatuslik olemus esitab sulle väljakutseid, sundides sind laiendama oma vaatenurka programmeerimiskeeled. See esoteeriline keel võimaldab teil hinnata kõrgema taseme keelte ilu ja vajalikkust, millega me oleme harjunud. See toob esile abstraktsioonide, korrektsete nimetamiskonventsioonide ja organiseeritud mälu paigutuse tähtsuse programmeerimiskeelte valdkonnas. See on midagi, mida Brainfuck oma minimalistliku, vaid kaheksast lihtsast käsust koosneva disainiga ei paku.
Brainfuck on Turingi terviklik keel, mis rõhutab veelgi selget ja sidusat lähtekoodi olulisust. Hoolimata sellest, et seda tunnustatakse kui üht kõige keerulisemat esoteerilist keelt, milles programme kirjutada, paistab see irooniliselt silma kui algaja lemmikkeel kõigile, kes soovivad luua oma Brainfucki kompilaatorit või Brainfucki interpretaatorit. Põhjuseks on selle käskude lihtsus ja asjaolu, et see ei nõua keerulist parsimist.
Brainfucki programmi loomine on ainulaadne kahel viisil. Esiteks tuleb kohaneda ühe mälumärgiga, mis sunnib teid oma lähtekoodist teistmoodi mõtlema. Ja teiseks, teil on olemas "nulli võimalus", mis on võimalus nullida mälurakend, mis on funktsioon, mis ei ole teistes formaalsetes programmeerimiskeeltes tavaline.
Õppimise osas on Brainfucki puhul rohkem, kui silmaga näha võib. Piisavalt aega ja õiget mõtteviisi arvestades on võimalik kirjutada sama programmi mitmel viisil, kasutades erinevaid Brainfucki koode. Selle teekonna viimane pool seisneb selles, et olla leidlik ja leida uusi, loomingulisi viise selle kuue sümboli kasutamiseks.
Brainfucki interpretaatorid on küll minimalistlikud, kuid annavad teile põhjaliku arusaama sellest, kuidas kood töötab, mida programm väljastab ja mis on Turingi tervikliku keele aluseks olev mehaanika. Lõppkokkuvõttes ei ole Brainfuck lihtsalt üks järjekordne esoteeriline programmeerimiskeel. See on täiesti uus mõõde, teistsugune arusaam sellest, kuidas me näeme, mõistame ja kirjutame programme.