Kirjautuminen

Haku

Tehtävät

Keskustelu: Projektit: Röda

Sivu 1 / 1

Sivun loppuun

fergusq [07.02.2016 22:08:29]

Lainaa #

Röda (lausutaan rööda) on uusin ohjelmointikieleni, jossa on monia edistyksellisiä ominaisuuksia. Suurin inspiraatio kielelle on ollut Bourne shell, mutta olen ottanut mukaan toteuttamiskelpoisia ajatuksia myös muista skriptikielistä. Yleisesti ottaen Röda on hyvin erilainen kuin useimmat muut kielet.

OhjelmointikieliJava 8
Viimeisin versio0.10-alpha
Kotisivuhttps://github.com/fergusq/roda
Latauslinkkihttp://kaivos.org/doc/röda.jar
Telegram-bottihttp://telegram.me/RoedaBot

Alla on esimerkki rödaskriptistä. Se on yksinkertainen ohjelma, joka lukee tiedoston ja tulostaa sen rivit rivinumeroiden kanssa.

#!/usr/bin/röda

function main(file) {
	linenum := 0
	readLines(file) | for line do
		print(linenum.." "..line)
		linenum ++
	done
}

Eräs tärkeimmistä Rödan ominaisuuksista on virrat, joiden avulla funktiot voivat palauttaa useita arvoja. Jokaisella funktiolla on sisääntulovirta ja ulostulovirta, joista voi lukea arvoja. Putkittamisen avulla monta funktiota voidaan kytkeä monisäikeisesti toisiinsa käsittelemään dataa ketjussa. Yllä olevassa esimerkissä readLines työntää ulostulovirtaansa tiedoston rivit, josta ne luetaan for-silmukalla.

Seuraavassa pätkässä haetaan Googlen kuvahaulla kuvia netistä:

sana := "<hakusana>"
user_agent := "Links (2.7; Linux 3.5.0-17-generic x86_64; GNU C 4.7.1; text)"
hakukone := "http://images.google.com/images?q="..sana.."&lr=lang_fi&cr=countryFI"
etsitty_url := "http://t[0-9]\\.gstatic\\.com/images\\?q=tbn:[a-zA-Z0-9_-]*"

i := 0
wcat(:U, user_agent, hakukone) | search(etsitty_url) | for kuva do
	wcat(:O, i, kuva)
	i++
done

Seuraava koodi luo listan kaikista hakukansioissa olevista ohjelmista:

path := [split(:s, ":", env["PATH"])]
komennot := [exec(:l, "ls", dir) for dir in path]

tai

komennot := [push(env["PATH"]) | split(:s, ":") | exec(:I, :l, "ls", dir) for dir]

Rödassa on vahva tyypitys sekä mahdollisuus käyttää tyyppiannotaatioita. Lisäksi kielessä on tuki luokille ja reflektiolle, joiden avulla on mahdollista luoda monipuolisia kirjastoja.

P. S. Kiitokset ylläpidolle syntaksivärityksen tukemisesta!

purkka [24.02.2016 20:22:54]

Lainaa #

miksi on olemassa wcat funktio? miksei vaan wget?

fergusq [25.02.2016 15:27:34]

Lainaa #

purkka kirjoitti:

(24.02.2016 20:22:54): miksi on olemassa wcat funktio? miksei vaan wget?

wcat on tosiaankin väännös wgetistä. Monet Rödalla tekemäni skriptit liittyvät jotenkin Internetiin ja siksi kyseiselle komennolle on tarvetta. Se jopa tukee lippuja -U ja -O, jotka on nimetty wgetin vastaavien lippujen mukaan.

En kuitenkaan halua, että Rödan komennot sekoittuvat Unix-komentoihin. Siksi nimesin komennon miten se on nimetty. Röda-ohjelma voi käyttää myös wget-komentoa seuraavalla koodilla:

wget := { |a...|; {} | exec "wget" *a | {} } /* {}| ja |{} sulkevat sisään- ja ulostulovirrat */

Tällä hetkellä suurin huoleni on komento time, jolla on Unix-vastine, joka tekee jotain aivan muuta. Minun pitäisi keksiä sille jokin hyvä toinen nimi. Huomasin myös sattumalta, että järjestelmääni on asennettu komento print, mutta tämä ei ole niin suuri ongelma, sillä kyseinen komento ei ole niin tunnettu tai käytetty.

fergusq [15.05.2016 22:50:54]

Lainaa #

Uusi versio 0.9-alpha on nyt kehityksen alla! Se tuo mukanaan unless- ja until-lauseiden lisäksi helpotetun syntaksin funktiokutsuille ja aritmetiikalle.

Testailin tässä huvikseni kieltäni ohjelmoimalla yksinkertaisia testejä. Huomasin hauskuudekseni, että alkulukujen laskeminen on mahdollista seuraavalla pienellä koodilla:

alkuluvut := (2)
seq 3 100 | for i do
	if [ i % a != 0 ] for a in alkuluvut; do
		print i
		alkuluvut += i
	done
done

Eli on mahdollista lisätä ehdon perään for alkio in taulukko, jos ehdon pitää päteä kaikille alkioille. En edes tajunnut, että niin voi tehdä, mutta asia on selvästi näin johtuen ehtolauseen semantiikasta. Kuten Bourne shellissäkin, myös Rödassa ehto on komento ja jokaisen komennon perään voi laittaa forin, jotta se suoritettaisiin monta kertaa. Ehtolauseen vartalo suoritetaan vain, jos yksikään ehtolauseen paluuarvo ei ole epätosi.

Käyttämällä lyhennyssyntaksia (for vartalon jälkeen), koodi voidaan tiivistää seuraavaksi, mutta en tiedä, onko se enää kovin luettavaa:

alkuluvut = (2)
seq 3 100 | { alkuluvut += i if [ i % a != 0 ] for a in alkuluvut } for i
print a for a in alkuluvut

Röda on muuten nopeampi generoimaan alkulukuja kuin Bash vastaavalla koodilla, mikä on minusta hieman yllättävää, vaikka Bashia ei kyllä ole varmaankaan tarkoitettu siihen.

Lisäys:

Tässä on esimerkki oikeasta ohjelmasta, jonka olen tehnyt Rödalla: http://kaivos.org:25565/. Se on simppeli wrapperi Wikialle, joka on välillä suorastaan ärsyttävä JavaScript-himmeleineen, jotka lagaavat puhelimilla ja joskus tietokoneellakin. On paljon nopeampi selata tätä. Koko HTTP-palvelin on koodattu alusta alkaen Rödalla, koodi siihen löytyy Githubista.

fergusq [31.05.2016 23:06:15]

Lainaa #

Olen päättänyt uudistaa kielen syntaksin kokonaan. Aiemmin se oli sekava ja monitasoinen ja saman asian tekemiseen oli monta eri tapaa. Aion yhdenmukaistaa syntaksia ja tehdä siitä selkeämpää ja ymmärrettävämpää.

Alla on lueteltu tähän mennessä tekemäni muutokset ja aivan lopussa on muutama kysymys. Olisin kiitollinen, jos joku vastaisi niihin.

SelitysRöda 0.9-aRöda 0.10-a
Funktiokutsulause
print "olen " ikä "-vuotias"
print "olen ", ikä, "-vuotias"
Listan luominen
("Maija" "Anne" "Liisa")
["Maija", "Anne", "Liisa"]
Laskutoimituksen tekeminen
print $(pisteet*3)
print pisteet*3
Upotettu yhden arvon palauttava funktiokutsu
palvelin = ![server 25565]
palvelin = server(25565)
Upotettu kutsu ja putkitus
salasana = ![cat "salasana.txt" | head]
salasana = cat("salasana.txt") | head()
Upotettu monta arvoa palauttava funktiokutsu
käyttäjät = !(cat "nimet.txt")
käyttäjät = [cat("nimet.txt")]
Neliölistan luominen 1
!(seq 1 1000 | push $(x*x) for x)
[seq(1, 1000) | push(x*x) for x]
Neliölistan luominen 2
!(push $(x*x) for x in !(seq 1 1000))
[push(x*x) for x in [seq(1, 1000)]]

Kysymyksiä

Mikä olisi hyvä syntaksi tyyppiparametreille ja -argumenteille?

Vanhassa Rödassa tyyppiargumentit määriteltiin nimen perässä kulmasulkeilla. Tämä ei aiheuttanut ongelmaa, sillä pienempi kuin ja suurempi kuin -operaattoreita ei saanut käyttää kuin aritmetiikkatilassa.

print ![funktio<tyyppi1, tyyppi2> 2]

Koska nyt aritmetiikkatilaa ei enää ole, esimerkiksi seuraava lause voi aiheuttaa ongelmia:

print(funktio<tyyppi1, tyyppi2>(2))
print((funktio<tyyppi1, tyyppi2>)(2)) /* oikea tulkinta  */
print((funktio<tyyppi1), (tyyppi2>2)) /* toinen tulkinta */

Muutamia saamiani ehdotuksia:

print(funktio:[tyyppi1, tyyppi2](2))
print(funktio<@tyyppi1, @tyyppi2>(2))
print(funktio[@tyyppi1, @tyyppi2](2))
print(funktio<<tyyppi1, tyyppi2>>(2))
print(funktio!(tyyppi1, tyyppi2)(2))

Pitäisikö sulut pakottaa myös lausetason funktiokutsuihin?

Nyt lausetasolla sulut voi jättää pois. Ne ovat kuitenkin joskus pakollisia, sillä joissakin tapauksissa koodi jäsennetään väärin ilman niitä. Pitäisikö ne pakottaa aina?

print nimi, " ", ikä  /* ilman sulkuja */
print(nimi, " ", ikä) /* sulkujen kanssa */

print [1]  /* yrittää ottaa "print-listan" toisen alkion ja kutsua sitä -> virhe */
print([1]) /* tulostaa listan "[1]" */

print time() | write "log.txt"  /* tulkitaan: */ print(time() | write("log.txt")) /* -> virhe, sillä write() ei palauta mitään */
print(time()) | write "log.txt" /* kirjoittaa ajan ja rivinvaihdon lokiin */

Pitäisikö += -operaattori poistaa?

Tällä hetkellä += -operaattoria voi käyttää asian lisäämiseksi listaan esimerkiksi seuraavasti:

lista = []
lista += "kissa"
lista += 2
print(lista) /* tulostaa [kissa, 2] */

Pitäisikö tämä operaattori poistaa, kuten eräät ovat minulle ehdottaneet? Itse pidän sitä todella käytännöllisenä. Rödassa on myös .=-operaattori, joka yhdistää listaan toisen listan.

vinsentti [02.06.2016 17:07:00]

Lainaa #

Kielen suurimpia laatutekijöitä ja tekijän kohtaamia vaikeuksia on yksityiskohtien yhteensopivuus. Yhteensopimattomuus ilmenee mm siten, että sama asia voidaan tehdä monella tavalla. Kysymyksiin yksityiskohdista on hyvin vaikeaa vastata ilman syvällistä perehtymistä. Gallupista ei ole ole juuri koskaan apua.

fergusq [04.06.2016 18:48:18]

Lainaa #

vinsentti kirjoitti:

(02.06.2016 17:07:00): Kielen suurimpia laatu­te­ki­jöitä ja tekijän...

Vastaaja ei tainnut huomata, että minä en kysynyt yksityiskohdista enkä edes siitä, mille asioille tulisi olla oma syntaksi. Kysymykseni sisälsi pintapuolisia ja esteettisiä ongelmia, joihin jokainen täällä oleva voi luultavasti muodostaa jonkinlaisen subjektiivisen kannan. Jokaisesta vastauksesta, myös huonoista, on minulle hyötyä ja saan niistä vertailukohtia muodostaakseni oman kantani. Lopullisen päätöksen teen minä itse, tiedänhän oman kieleni parhaiten. Gallupissa ei ole mitään vikaa.

Mutta olet oikeassa siinä, että gallupista ei ole välttämättä apua. Ohjelmointiputkassa on näet uskomattoman vähän ihmisiä, jotka jaksavat ylipäätänsä vastata gallupeihin, saatikka sitten kiinnostuneet minun kielestäni. Edellinen vähänkään kiinnostunut ihminen ragequittasi saatuaan kuulla sen (kieltämättä järkyttävän) faktan, että Forth ei sovi aloittelijoille. Minä olen myös yrittänyt olla kiinnostunut muiden henkilöiden vastaavista projekteista, heikoin tuloksin. Ohjelmointiputkan keskustelukulttuuri on uskomattoman epäkannustava.

vinsentti [04.06.2016 19:20:00]

Lainaa #

fergusq kirjoitti:

Ohjelmointiputkassa on näet uskomattoman vähän ihmisiä, jotka jaksavat ylipäätänsä vastata gallupeihin, saatikka sitten kiinnostuneet minun kielestäni. Ohjelmointiputkan keskustelukulttuuri on uskomattoman epäkannustava.

Koko maailmassa on vähän ihmisiä, jotka ovat kiinnostuneita sellaisistakin asioista kuin rakenteellinen ohjelmointi tai olio-ohjelmointi. Kannanottoja kaverin aikaansaannoksiin, esim ohjelmointikieleen rajoittaa kyllä vaadittava effortti. Usein on vaikea sanoa, onko kysymys periaatteesta vai yksityiskohdasta. Sanonnan "piru piilee yksityiskohdissa" sisältö on juuri tämä: pitäisi jaksaa perehtyä.

fergusq [04.06.2016 20:55:55]

Lainaa #

Olet kyllä oikeassa siinä, että hyvin harva jaksaa täysin perehtyä niinkin monimutkaisen asian kuin ohjelmointikieli yksityiskohtiin. Varsinkin, kun on kyse Rödan kaltaisesta erittäin epätavallisesta kielestä, jonka ajattelumalli virtoineen ja säikeineen erilainen kuin muissa kielissä (paitsi juuri komentosarjakielissä). En esimerkiksi usko, että kukaan täällä täysin ymmärtää, mitä rivi print(time()) | write("log.txt") tekee ja miten se toimii. (Aion muuten varmaan rikkoa tuon ja lopettaa I/O:n käsittelyn pääfunktion virroissa, sillä nyt funktio ei voi tulostaa mitään, jos se palauttaa arvon tai jos sitä kutsutaan funktiosta, joka palauttaa arvon, mikä on hieman ärsyttävää.)

Esittämäni kysymykset, varsinkin ensimmäinen, liittyvät kuitenkin enemmän kauneuteen kuin ohjelman logiikkaan. Minä annan useamman ehdotetun vaihtoehdon tyyppiargumenttien syntaksiksi, joista jokainen voi valita suosikkinsa tai esittää uusia vaihtoehtoja. Minkäänlaista ymmärrystä mistään Rödan ominaisuudesta ei vaadita.

Metabolix [04.06.2016 21:27:21]

Lainaa #

Itse laittaisin tyyppeihin vaikka @-merkin ja mieluiten ihan tavalliset sulut. En ihan ymmärrä (enkä jaksanut selvittää), mitä ovat nämä tyyppiargumentit funktion kutsuvaiheessa, ts. mitä tekisi jokin tällainen funktio@(A,B)(1). Jos tyypit vaikuttavat suoraan ohjelman toimintaan eivätkä vain tuota funktiosta erilaisia versioita (kuten C++:n malleissa), onko edes tarpeen käsitellä tyypit ja data erikseen vai voisiko nämä yhdistää (kuten JavaScriptissa)?

fergusq kirjoitti:

Nyt funktio ei voi tulostaa mitään, jos se palauttaa arvon.

Sehän on tavallaan hieno ominaisuus ja auttaa tekemään funktionaalisten kielten tyyliin porttautuvia funktioita, joilla on vähemmän sivuvaikutuksia kuten odottamatonta tulostetta.

fergusq [04.06.2016 21:59:30]

Lainaa #

Metabolix kirjoitti:

Itse laittaisin tyyppeihin vaikka @-merkin ja mieluiten ihan tavalliset sulut. En ihan ymmärrä (enkä jaksanut selvittää), mitä ovat nämä tyyppiargumentit funktion kutsuvaiheessa, ts. mitä tekisi jokin tällainen funktio@(A,B)(1). Jos tyypit vaikuttavat suoraan ohjelman toimintaan eivätkä vain tuota funktiosta erilaisia versioita (kuten C++:n malleissa), onko edes tarpeen käsitellä tyypit ja data erikseen vai voisiko nämä yhdistää (kuten JavaScriptissa)?

Tyyppiparametreja ja -argumentteja voi käyttää vaikka näin (sinun syntaksillasi):

record MyRecord(v) {
	val : integer = v
}

function f@(A,B)(p : A) {
	return new B(p)
}

function main() {
	print(f@(integer,MyRecord)(2))
}

On jotenkin selkeämpää, että tyypit ovat omassa nimiavaruudessaan. JavaScript kärsii suuresti siitä, kuinka hankalasti hahmotettava tyypin käsite on. Nyt funktiosta ei varsinaisesti luoda uutta versiota (esimerkiksi niin, että sen voisi laittaa muuttujaan f = funktio@(integer), mutta tällainen ominaisuus on helposti mahdollista toteuttaa.

Saman voi toki tehdä myös reflektiolla:

function f(my_type, p) {
	return my_type.newInstance(p)
}

function main() {
	print(f(reflect MyRecord, 2))
}

vinsentti [05.06.2016 10:22:40]

Lainaa #

fergusq kirjoitti:

kuinka hankalasti hahmotettava tyypin käsite on

Tyyppiparametreja sanotaan joskus (ainakin C++) geneeriseksi paradigmaksi. Vain taivas on rajana, kun ajatellaan, mitä kaikkea niillä voidaan tehdä. Siitä ylennys paradigmojen kastiin, joista jokainen vaatii veronsa harjoittajaltaan. Verotus on kovaa, kun kielessä on paljon paradigmoja. Menee vaikeaksi.

Oskuz [06.06.2016 14:52:56]

Lainaa #

Tyyppiparametreille käyttäisin Metabolixin ehdottamaan syntaksia. Sulut pitäs pakottaa selkeyden vuoksi ja += on kiva lisä .= lisäksi.

Metabolix [06.06.2016 17:55:54]

Lainaa #

Tyyppiparametrien merkintä voisi yhtä hyvin olla myös tällainen: funktio(@A, @B, 2). Tyyppien ei olisi välttämätöntä olla samassa, vaan ne voisi funktion esittelyssäkin luetella muiden parametrien joukossa loogisemmissa kohdissa.

fergusq [08.06.2016 09:07:53]

Lainaa #

Haluaisin, että tyyppiparametrien syntaksi olisi johdonmukainen sekä tietueita että funktioita käsiteltäessä. Tietueilla voi olla myös tavallisia parametreja (jotka muodostavat eräänlaisen konstruktorin), mutta näitä ei tietenkään anneta esimerkiksi kentän tyypin määriteltäessä, joten tyyppiparametrien laittaminen niiden sekaan olisi melko sekavaa.

record LinkattuLista@(T)(t) {
	sisältö : T = t
	linkki : LinkattuLista@(T)
}

function teeLinkattuLista@(T)(arvot : list@(T)) {
	lista := new LinkattuLista@(T)(arvot[0])
	kohta := lista
	for arvo in arvot[1:] do
		uusi_kohta := new LinkattuLista@(T)(arvo)
		kohta.linkki = uusi_kohta
		kohta = uusi_kohta
	done
	return lista
}

Jos tyyppiparametrit sotkettaisiin muiden parametrien sekaan, tulos voisi olla hieman sekava:

record LinkattuLista(@T, t) { /* <-- tyyppiparametri ja tavallinen parametri */
	sisältö : @T = t
	linkki : LinkattuLista(@T) /* <-- vain yksi argumentti */
}

function teeLinkattuLista(@T, arvot : @list(@T)) {
	lista := new @LinkattuLista(@T, arvot[0]) /* <-- kaksi argumenttia */
	kohta := lista
	for arvo in arvot[1:] do
		uusi_kohta := new @LinkattuLista(@T, arvo)
		kohta.linkki = uusi_kohta
		kohta = uusi_kohta
	done
	return lista
}

Tällä hetkellä Röda tukee annotaatioita, jotka käyttävät niin ikään @-merkkiä. Teknisesti se, että tyypeillä ja annotaatioilla on sama etuliite, ei aiheuta ongelmia, mutta se voi olla hieman sekavaa.

fergusq [25.11.2016 20:48:03]

Lainaa #

Miten minun kannattaisi nimetä seuraava ominaisuus?

split-funktiolla on kaksi tilaa. Ensimmäinen tila työntää ulostuloon pilkotun merkkijonon osat sellaisenaan. Toinen tila työntää ulostulovirtaan arrayn, joka sisältää pilkotun merkkijonon osat.

Siis näin:

/* split pilkkoo oletuksena välilyönnistä */
ulostulo := [split("kissa söi kalaa", "koira söi lihaa")]
print(ulostulo) /* ["kissa", "söi", "kalaa", "koira", "söi", "lihaa"] */

ulostulo := [split(:c, "kissa söi kalaa", "koira söi lihaa")]
print(ulostulo) /* [["kissa", "söi", "kalaa"], ["koira", "söi", "lihaa"]] */

Molemmilla tiloilla on omat käyttötarkoituksensa. Ensimmäinen tila on hyödyllinen, jos merkkijonoja on vain yksi, kun taas toinen on kätevämpi usean merkkijonon kanssa. Käytännön esimerkki voisi olla esim. "abc;def;ghi"-tyylisen merkkijonon parsiminen (tämä on aito pätkä eräästä ohjelmastani):

/* split(:s, "c") pilkkoo c-merkin kohdalta, structure on merkkijono */
push(structure) | split(:s, ";") | split(:c, :s, "") | for group do
	/* group on lista merkkejä */
done

(split voi ottaa syötteen siis joko argumenttina tai sisääntulovirrastaan putkituksen avulla)

Minusta :c on rumaa syntaksia (samoin :s). Siksi aionkin jakaa split-funktion kahdeksi funktioksi. Mitkä olisivat hyvät nimet näille funktioille, joista toinen laittaa saman merkkijonon osat listaan ja toinen palauttaa ne kaikki samassa?

jlaire [26.11.2016 06:43:25]

Lainaa #

Tuntuu omituiselta, että split hyväksyy useamman kuin yhden splitattavan argumentin. Jos funktioiden yhdistely on helppoa, jokainen voi ajaa vain yhden asian.

Eikö olisi yleiskäyttöisempää tarjota map-funktio ja ilmaista tuo :c-versio muodossa map split, kuten monissa muissa kielissä? Ensimmäinen versio voisi olla map split | concat tai miten se nyt kielessä ilmaistaankaan. Haskellissa tämä on niin yleinen asia, että standardikirjastosta löytyy myös concatMap split.

fergusq [26.11.2016 23:32:05]

Lainaa #

Huomasit juuri yhden epäloogisuuden, joka Rödassa on. Periaatteessa kielessä on kahdenlaisia funktioita: sellaisia, jotka ottavat syötteen sisääntulovirrasta (split, match, search, replace, ...), sekä sellaisia, jotka ottavat argumentteja (fileExists, seq, ...).

Sisääntulovirrasta lukevat funktiot liittyvät suurin osa jotenkin merkkijonojen käsittelyyn. Niissä ikään kuin oletetaan, että sisääntulovirta olisi jotenkin yhtenäinen asia, kuten se usein on. Esimerkiksi tiedostoja luettaessa voi kirjoittaa

readLines("file.txt") | split() | replace("\\W", "") | for word do
	/* ... */
done

readLines palauttaa työntää tiedoston rivit merkkijonoina virtaan, minkä jälkeen jokainen pilkotaan välilyöntien kohdalta ja lopuksi erikoismerkit poistetaan. For-silmukassa käydään siis läpi jokainen tiedoston kirjaimista koostuva sana.

Toki on epäselvää, että jotkin funktiot tukevat tätä ja jotkut eivät. Lisäksi split ja match tukevat vielä lisäksi argumentteja käytännöllisyyden vuoksi, mikä entisestään monimutkaistaa asiaa.

Rödassa on sisäänrakennettu syntaksi map-funktion kaltaiselle toiminnolle. Jos esimerkiksi fileExists-funktiota haluaisi käyttää keskellä virtaa, voisi kirjoittaa seuraavasti:

readLines("fileNames.txt") | fileExists(fileName) for fileName | for doesExist do
	/* ... */
done

Tällaista tarvitsee melko harvoin, eikä tuo esimerkkikään ole kovin järkevä (miksi kukaan haluaisi loopata totuusarvoja?). Jos oikeasti haluaa tehdä noin, on selkeämpää kirjoittaa se eksplisiittisesti. Siksi kaikkiin funktioihin ei ole rakennettu tukea virroille.

Yksi ratkaisu olisi poistaa virtatoiminto kaikista funktioista, mutta en haluaisi tehdä sitä, sillä ominaisuus on todella käytännöllinen varsinkin, jos putkitettuja komentoja on hyvin monta peräkkäin. Alla on kuvitteellinen esimerkki, joka on kirjoitettu ilman virtatoimintoa.

readLines("file.txt") | split(line) for line | replace("\\W", "", fragment) for fragment | for word do
	/* ... */
done

Kuvitteellinen siksi, että replace ei tällä hetkellä tue merkkijonon ottamista kolmantena argumenttina. Esimerkistä näkee, kuinka sekavaksi koodi muuttuu for-rakenteiden lisäämisen jälkeen.

Eräs vaihtoehto olisi tehdä jokaisesta funktiosta kaksi eri versiota: virrasta lukeva ja argumentteja ottava. Olisiko se hyvä ratkaisu? Mikä olisi hyvä nimeämiskäytäntö näille funktioille?

(PS. Uudelleennimesin catin readLinesiksi, se on selvempi. Nuo syntaksiväritykset ovat aika vanhentuneet, joten ehkä olisi parempi, jos pelkät avainsanat värjättäisiin. Funktioiden lista muuttuu aika nopeasti, koska kieli ei ole vielä valmis. Avainsanat on lueteltu täällä. Kiitos paljon moderaattorille kielen tukemisesta!)

tepokas [27.11.2016 21:25:03]

Lainaa #

Unohda tuo funktio-ideologia. Keskity pelkästään virta-ideologiaan.

Määrittele siten, että () on vakiomuotoinen virta (atomi), funktionimi on nimettyvirta (kiinnitetty muuttuja) ja | putkituskomento eli yhdiste kahdelle virralle.

Nyt voit suorittaa "funktio kutsun" vaikkapa seuraavasti: (("file.txt")|tiedosto)|readLines

missä (("file.txt")|tiedosto) tarkoittaa,että tiedostonimi "file.txt" syötetään virralle tiedosto ja tiedosto syötetään virralle (funktiolle) readLines. Tällätavoin pääset eroon funktioiden kahden version ongelmasta.

jlaire [28.11.2016 09:18:01]

Lainaa #

fergusq kirjoitti:

readLines("file.txt") | split(line) for line | replace("\\W", "", fragment) for fragment | for word do
	/* ... */
done

Kuvitteellinen siksi, että replace ei tällä hetkellä tue merkkijonon ottamista kolmantena argumenttina. Esimerkistä näkee, kuinka sekavaksi koodi muuttuu for-rakenteiden lisäämisen jälkeen.

Eräs vaihtoehto olisi tehdä jokaisesta funktiosta kaksi eri versiota: virrasta lukeva ja argumentteja ottava. Olisiko se hyvä ratkaisu? Mikä olisi hyvä nimeämiskäytäntö näille funktioille?

Jos suurin syy kahteen eri versioon on koodin sekavuus, parempi ratkaisu olisi minusta keksiä for-rakenteita kätevämpi syntaksi.

For-rakenteet muistuttavat vähän lambdoja. Miten olisi vaikka tällainen, kuten Scalassa:

readLines("file.txt") | split(_) | replace("\\W", "", _) | for word do
	/* ... */
done

fergusq [28.11.2016 14:07:41]

Lainaa #

tepokas kirjoitti:

Unohda tuo funktio-ideologia. Keskity pelkästään virta-ideologiaan.

Olisi kiintoisaa tehdä kieli, joka perustuu kokonaan virroille. Valitettavasti Rödaa on vaikea viedä siihen suuntaan, sillä funktioiden argumenteilla on tarkoituksensa. Esimerkiksi replace-funktion argumenteilla annetaan tietoa suoritettavasta operaatiosta, kun taas virta sisältää käsiteltävän datan. Pitäisikö funktioilla olla monta sisäänmenovirtaa erityyppisille argumenteille?

Kieli, jossa on pelkkiä virtoja, on kuitenkin niin kiva idea, että voisin toteuttaa joskus sellaisen. En kuitenkaan usko, että siitä saisi kovin käyttökelpoisen.

jlaire kirjoitti:

Jos suurin syy kahteen eri versioon on koodin sekavuus, parempi ratkaisu olisi minusta keksiä for-rakenteita kätevämpi syntaksi.

For-rakenteet muistuttavat vähän lambdoja. Miten olisi vaikka tällainen, kuten Scalassa:

readLines("file.txt") | split(_) | replace("\\W", "", _) | for word do
	/* ... */
done

Tuo kuulostaa hyvältä idealta. Alaviivasyntaksin avulla mitä tahansa funktiota voi käyttää helposti virran keskellä.

Funktiot voisi jakaa niiden käyttötarkoituksen mukaan seuraaviin luokkiin:

Tavoite olisi, että funktiosta pystyisi helposti päättelemään, miten sitä käytetään. Arvoja käsittelevien funktioiden kanssa käytettäisiin alaviivaa ja virtaa käsittelevien funktioiden kanssa ei.

/* Ottaa aakkosjärjestyksessä 10 ensimmäistä sanaa */
readLines("sanat.txt") | split(_) | sort() | head(10) | writeLines("sanat2.txt")

Toteutin kieleen muuten Python-tyyliset nimetyt argumentit. Nyt split-funktiolle voi antaa erotinmerkin syntaksilla split(sep=","), eikä tarvitse käyttää rumaa split(:s, ",")-syntaksia.

tepokas [29.11.2016 22:37:53]

Lainaa #

Funktion parametrit voi nähdä vaikkapa siten että merkinnässä (("file.txt")|tiedosto) on merkkijono "file.txt" on _tyyppiä_ tiedosto tai tiedosto on parametrin "file.txt" nimi. Tai että tiedosto nimeltä "" toimitetaan könttänä Readlines-operaation inputiin ja Readlines poimii siitä rivit. Miten sen sitten haluaa ilmaista.

Virta-olio voi tulkata saapuvaa tietoa ja toimia parametrien tyypin tai nimen mukaan, miksi sitä sitten sanotkaan. Tällöin ei tarvita kahtaa eri syöte- tai inputti-virtaa.

Kirjassa nimeltä "Concepts, Techniques, and Models of Computer Programming" on esitetty monia eri näkökantoja ohjelmointikielen toteutukseen ja kielen oikeaksi todistamiseen, jos isommin alkaa todistaminen kiinnostamaan, kannattaa lukea. Kirja oli ennen vapaasi netti-levityksessä, nykypäivästä en tiedä.

fergusq [30.11.2016 15:17:06]

Lainaa #

tepokas kirjoitti:

Kirjassa nimeltä "Concepts, Techniques, and Models of Computer Programming" on esitetty monia eri näkökantoja ohjelmointikielen toteutukseen ja kielen oikeaksi todistamiseen, jos isommin alkaa todistaminen kiinnostamaan, kannattaa lukea. Kirja oli ennen vapaasi netti-levityksessä, nykypäivästä en tiedä.

Mitä tarkoitat ohjelmointikielen todistamisella oikeaksi? Mitä se on englanniksi? Aion kyllä määritellä kielen formaalisti jossain vaiheessa, kunhan jaksan. Löysin kirjan netistä ja se vaikuttaa ihan mielenkiintoiselta.

vinsentti [02.12.2016 10:15:40]

Lainaa #

tepokas kirjoitti:

"Concepts, Techniques, and Models of Computer Programming"

Kirjassa puhutaan ohjelmista päättelemisestä, mutta ei mennä asiaan tavanomaista enempää. Kääntäjät tavanomaisesti päättelevät esim tyyppien yhteensopivuudesta, mutta eivät päättele, että ohjelma vastaa speksiä.
Kirjan käyttämä kieli Oz on kaikkien paradigmojen opetus- ja tutkimusalusta. Toisessa ääripäässä Meyerin Object Oriented Software Construction-kirjan Eiffel kieli on puhtaasti olioparadigmaan perustuva käytännön ohjelmointikieli, joka menee päättelyasiassa tavanomaista pidemmälle.


Sivun alkuun

Vastaus

Muista lukea keskustelun ohjeet.
Tietoa sivustosta