(toiminnot)

hwechtla-tl: Clojuren lukeminen ja makrot

Kierre.png

Mikä on WikiWiki?
nettipäiväkirja
koko wiki (etsi)
viime muutokset


(nettipäiväkirja 21.12.2015) Voisin mainita, että Clojure on ollut mielenkiintoinen tutustuttava, mutta kielen kokeellisuus näkyy sekä hyvässä että pahassa. Kun jossain Pythonissa syntaksi vakiinnutetaan PEP:llä, jos sille koetaan riittävästi tarvetta, Clojuressa joku ryntää heti ensimmäiseksi kehittelemään oman DSL:n Clojuren sisään ja mahdollisesti toteuttaa makron tai pari, jotka tekevät DSL:n käytöstä "siistin näköistä".

Seuraus on se, että Clojure-koodia lukiessaan ei koskaan voi oikein luottaa siihen, että funktiokutsulta näyttävät asiat ovat funktiokutsuja, ja joskus virheilmoitukset ovat tosi outoja, koska ne seuraavat makroekspansiokoodin oletuksista, jotka eivät toteudu (esim. jossain kohdassa on lista kun pitäisi olla vektori). Erilaisia makropohjaisia binding formeja on tosi paljon, ja koska Clojuressa on aika monipuoliset sisäänrakennetut syntaktiset muodot, makrot voivat vapaasti sekoittaa listoja, vektoreita, mappeja, setteja, symboleita ja keywordeja ja antaa niille kaikenlaisia merkityksiä.

Pari esimerkkiä: Clojuren require-kieli on suunnilleen samanlainen kuin Pythonin import-statementin eri muodot, mutta toteutettu lennokkaasti DSL:nä, jossa erilaisilla keywordeilla on syntaktisia sisältöjä. Esimerkiksi, kun Pythonissa sanottaisiin:

from mylib.harvest import urlfind, babel

... niin Clojuressa sanottaisiin:

(require '[mylib.harvest :refer [urlfind babel]])

Toinen esimerkki: Pythonissa (ja Haskellissa, Goferissa jne.) on listakeräelmät, joilla voi tehdä kaikenlaista monadista. Clojuressa ei ole näitä samassa muodossa, mutta sen sijaan erilaisia iteraattoreita (map, filter, reduce, jne) voi yhdistellä threading macroilla, joista lisää täällä: http://jdevuyst.blogspot.fi/2013/11/thoughts-on-clojure-threading-macros.html . Sitten kun tällaista koodia lukee, on paras tietää, että nämä makrot eivät ole oikeasti funktioita.

Kolmas esimerkki: yksi Clojuren monipuolisimpia koodinlyhentäjiä on destrukturointi, jolla saa vedetyksi ja bindatuksi muuttujiin monimutkaisesta tietorakenteesta juuri ne osat, jotka haluaa. Tämä destrukturointikieli on aikamoinen DSL, joka rakentuu ennen kaikkea mappien ja keywordien varaan. Siihen voi tutustua esim. täällä: https://gist.github.com/john2x/e1dca953548bfdfb9844

Itseäni ehkä tässä kiusaa eniten se, että minusta tämä kompromissitie syntaktisen sokerin ja sen puuttumisen välillä ei ole ihan fiksu. Minusta makrojen käyttöä lähinnä vaikeuttaa se, että niissä voidaan sekoittaa niin monenlaisia elementtejä. Perinteisessä Lispissä oli sekä käytännössä helpointa että sanaton sopimus toteuttaa sellaisia makroja, jossa kunkin listaformin eli suljelausekkeen ensimmäinen symboli kertoo, miten se tulkitaan - sekä top-level formissa että kaikissa sen sisällä olevissa. Tämä teki helpoksi suunnitella DSL:aa: jos makrossa tarvitaan useammanlaisia määrityksiä, varataan listan ensimmäinen symboli tyyppikäyttöön, jos ei, niin käytetään listoja vain. Se, että voi valita listoista, vektoreista ja muista sekä käyttää vielä keskellä tietorakenteita olevia keywordeja antamaan lisätietoa monimutkaistaa DSL:ia ja vaikeuttaa niiden muistamista antamatta mielestäni kummoistakaan lisäarvoa.


kommentoi (viimeksi muutettu 21.12.2015 12:42)