TIEA341 Funktio-ohjelmointi 1, kevät 2008

Samankaltaiset tiedostot
5.5 Jäsenninkombinaattoreista

TIEA341 Funktio-ohjelmointi 1, kevät 2008

TIEA341 Funktio-ohjelmointi 1, kevät 2008

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Jäsennys. TIEA341 Funktio ohjelmointi 1 Syksy 2005

TIEA341 Funktio-ohjelmointi 1, kevät 2008

TIEA341 Funktio-ohjelmointi 1, kevät 2008

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Algebralliset tietotyypit ym. TIEA341 Funktio ohjelmointi 1 Syksy 2005

jäsentämisestä TIEA241 Automaatit ja kieliopit, syksy 2015 Antti-Juhani Kaijanaho 27. marraskuuta 2015 TIETOTEKNIIKAN LAITOS

tään painetussa ja käsin kirjoitetussa materiaalissa usein pienillä kreikkalaisilla

jäsentäminen TIEA241 Automaatit ja kieliopit, syksy 2015 Antti-Juhani Kaijanaho 26. marraskuuta 2015 TIETOTEKNIIKAN LAITOS

jäsennyksestä TIEA241 Automaatit ja kieliopit, syksy 2016 Antti-Juhani Kaijanaho 29. syyskuuta 2016 TIETOTEKNIIKAN LAITOS Kontekstittomien kielioppien

TIEA241 Automaatit ja kieliopit, kesä Antti-Juhani Kaijanaho. 10. kesäkuuta 2013

815338A Ohjelmointikielten periaatteet Harjoitus 7 Vastaukset

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 30. marraskuuta 2015

Tyyppejä ja vähän muutakin. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Abstraktit tietotyypit. TIEA341 Funktio ohjelmointi 1 Syksy 2005

Laajennetaan vielä Ydin-Haskellia ymmärtämään vakiomäärittelyt. Määrittely on muotoa

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

Esimerkki: Laskin (alkua) TIEA341 Funktio ohjelmointi 1 Syksy 2005

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 3. lokakuuta 2016

Luku 3. Listankäsittelyä. 3.1 Listat

Jatkeet. TIES341 Funktio ohjelmointi 2 Kevät 2006

Ydin-Haskell Tiivismoniste

TIEA241 Automaatit ja kieliopit, kevät 2011 (IV) Antti-Juhani Kaijanaho. 19. tammikuuta 2012

Tämän vuoksi kannattaa ottaa käytännöksi aina kirjoittaa uuden funktion tyyppi näkyviin, ennen kuin alkaa sen määritemää kirjoittamaan.

Täydentäviä muistiinpanoja kontekstittomien kielioppien jäsentämisestä

Attribuuttikieliopit

Tyyppiluokat II konstruktoriluokat, funktionaaliset riippuvuudet. TIES341 Funktio-ohjelmointi 2 Kevät 2006

TIEA241 Automaatit ja kieliopit, kevät Antti-Juhani Kaijanaho. 12. kesäkuuta 2013

Haskell ohjelmointikielen tyyppijärjestelmä

Geneeriset tyypit. TIES542 Ohjelmointikielten periaatteet, kevät Antti-Juhani Kaijanaho. Jyväskylän yliopisto Tietotekniikan laitos

2.4 Normaalimuoto, pohja ja laskentajärjestys 2.4. NORMAALIMUOTO, POHJA JA LASKENTAJÄRJESTYS 13

TIEA241 Automaatit ja kieliopit, kevät Antti-Juhani Kaijanaho. 2. helmikuuta 2012

Uusi näkökulma. TIEA341 Funktio ohjelmointi 1 Syksy 2005

TIEA241 Automaatit ja kieliopit, kevät Antti-Juhani Kaijanaho. 16. helmikuuta 2012

Laiska laskenta, korekursio ja äärettömyys. TIEA341 Funktio ohjelmointi Syksy 2005

TIEA241 Automaatit ja kieliopit, kevät Antti-Juhani Kaijanaho. 26. tammikuuta 2012

Kontekstittomien kielten jäsentäminen Täydentäviä muistiinpanoja TIEA241 Automaatit ja kieliopit, syksy 2016

Vasen johto S AB ab ab esittää jäsennyspuun kasvattamista vasemmalta alkaen:

Monadeja siellä, monadeja täällä... monadeja kaikkialla? TIES341 Funktio ohjelmointi 2 Kevät 2006

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 16. marraskuuta 2015

Lisää laskentoa. TIEA341 Funktio ohjelmointi 1 Syksy 2005

TIES542 kevät 2009 Denotaatio

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 3. joulukuuta 2015

Laskennan mallit (syksy 2010) Harjoitus 8, ratkaisuja

Luku 4. Tietorakenteet funktio-ohjelmoinnissa. 4.1 Äärelliset kuvaukset

Jäsennysalgoritmeja. TIE448 Kääntäjätekniikka, syksy Antti-Juhani Kaijanaho. 29. syyskuuta 2009 TIETOTEKNIIKAN LAITOS. Jäsennysalgoritmeja

Alityypitys. TIES542 Ohjelmointikielten periaatteet, kevät Antti-Juhani Kaijanaho. Jyväskylän yliopisto Tietotekniikan laitos

TIEA241 Automaatit ja kieliopit, kevät Antti-Juhani Kaijanaho. 12. tammikuuta 2012

Demo 7 ( ) Antti-Juhani Kaijanaho. 9. joulukuuta 2005

Logiikan kertausta. TIE303 Formaalit menetelmät, kevät Antti-Juhani Kaijanaho. Jyväskylän yliopisto Tietotekniikan laitos.

Ohjelmoinnin peruskurssien laaja oppimäärä

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin peruskurssien laaja oppimäärä

Tietorakenteet ja algoritmit - syksy

Ohjelmoinnin peruskurssien laaja oppimäärä

Taas laskin. TIES341 Funktio ohjelmointi 2 Kevät 2006

TIEA241 Automaatit ja kieliopit, kesä Antti-Juhani Kaijanaho. 29. toukokuuta 2013

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 5. marraskuuta 2015

TIEA241 Automaatit ja kieliopit, kevät 2011 (IV) Antti-Juhani Kaijanaho. 31. maaliskuuta 2011

Ohjelmoinnin peruskurssien laaja oppimäärä

Säännölliset kielet. Sisällys. Säännölliset kielet. Säännölliset operaattorit. Säännölliset kielet

TIEA241 Automaatit ja kieliopit, kevät 2011 (IV) Antti-Juhani Kaijanaho. 31. maaliskuuta 2011

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 12. marraskuuta 2015

Ohjelmoinnin peruskurssien laaja oppimäärä

5.3 Laskimen muunnelmia 5.3. LASKIMEN MUUNNELMIA 57

Funktionimien kuormitus. TIES341 Funktio ohjelmointi 2 Kevät 2006

TIEA241 Automaatit ja kieliopit, kevät Antti-Juhani Kaijanaho. 8. maaliskuuta 2012

ITKP102 Ohjelmointi 1 (6 op)

Tietorakenteet ja algoritmit Johdanto Lauri Malmi / Ari Korhonen

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 19. syyskuuta 2016

vaihtoehtoja TIEA241 Automaatit ja kieliopit, syksy 2016 Antti-Juhani Kaijanaho 13. lokakuuta 2016 TIETOTEKNIIKAN LAITOS

follow(a) first(α j ) x

Pinoautomaatit. TIEA241 Automaatit ja kieliopit, kesä Antti-Juhani Kaijanaho. 6. kesäkuuta 2013 TIETOTEKNIIKAN LAITOS. Pinoautomaatit.

Ohjelmointi 1 C#, kevät 2013, 2. tentti

Ohjelmoinnin perusteet Y Python

ITKP102 Ohjelmointi 1 (6 op)

Hahmon etsiminen syotteesta (johdatteleva esimerkki)

Algoritmit 1. Luento 4 Ke Timo Männikkö

Laskennan rajoja. Sisällys. Meta. Palataan torstaihin. Ratkeavuus. Meta. Universaalikoneet. Palataan torstaihin. Ratkeavuus.

TIEA341 Funktio-ohjelmointi 1, kevät 2008

Pinoautomaatit. Pois kontekstittomuudesta

1. (a) Seuraava algoritmi tutkii, onko jokin luku taulukossa monta kertaa:

TIEA241 Automaatit ja kieliopit, kevät 2011 (IV) Antti-Juhani Kaijanaho. 29. huhtikuuta 2011

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 12. lokakuuta 2016

Ohjelmoinnin peruskurssien laaja oppimäärä

Ohjelmoinnin perusteet Y Python

TIEA341 Funktio-ohjelmointi 1, kevät 2008

1. Mitä tehdään ensiksi?

Ohjelmoinnin peruskurssien laaja oppimäärä

TAMPEREEN TEKNILLINEN YLIOPISTO

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 9. lokakuuta 2016

Jäsennysaiheesta lisää Täydentäviä muistiinpanoja TIEA241 Automaatit ja kieliopit, syksy 2016

Täydentäviä muistiinpanoja jäsennysalgoritmeista

TAMPEREEN TEKNILLINEN YLIOPISTO

Interaktiivisten järjestelmien arkkitehtuuriratkaisu, jolla käyttöliittymä erotetaan sovelluslogiikasta.

Laskennan rajoja. TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 10. joulukuuta 2015 TIETOTEKNIIKAN LAITOS.

Transkriptio:

TIEA341 Funktio-ohjelmointi 1, kevät 2008 Luento 9 Kombinaattoreista Antti-Juhani Kaijanaho Jyväskylän yliopisto Tietotekniikan laitos 21. tammikuuta 2008

Currying Haskell-funktio ottaa aina vain yhden parametrin: f : : p a r a m e t r i t y y p p i > p a l u u t y y p p i f p a r a m e t r i = p a l u u a r v o... f a r g u m e n t t i... Mutta funktio voi palauttaa funktion: f : : p a r a m e t r i t y y p p i 1 > ( p a r a m e t r i t y y p p i 2 > p a l u u t y y p p i ) f p a r a m e t r i 1 = \ p a r a m e t r i 2 > p a l u u a r v o... ( f a r g u m e n t t i 1 ) a r g u m e n t t i 2

Julistetaan, että funktion soveltaminen assosioi vasemmalle ja funktiotyypin nuoli oikealle. Nyt tämä f : : p a r a m e t r i t y y p p i 1 > ( p a r a m e t r i t y y p p i 2 > p a l u u t y y p p i ) f p a r a m e t r i 1 = \ p a r a m e t r i 2 > p a l u u a r v o... ( f a r g u m e n t t i 1 ) a r g u m e n t t i 2 on sama kuin f : : p a r a m e t r i t y y p p i 1 > p a r a m e t r i t y y p p i 2 > p a l u u t y y p p i f p a r a m e t r i 1 = \ p a r a m e t r i 2 > p a l u u a r v o... f a r g u m e n t t i 1 a r g u m e n t t i 2

Julistetaan vielä, että f p a r a m e t r i 1 = \ p a r a m e t r i 2 > p a l u u a r v o on sama kuin f p a r a m e t r i 1 p a r a m e t r i 2 = p a l u u a r v o niin saadaan f : : p a r a m e t r i t y y p p i 1 > p a r a m e t r i t y y p p i 2 > p a l u u t y y p p i f p a r a m e t r i 1 p a r a m e t r i 2 = p a l u u a r v o... f a r g u m e n t t i 1 a r g u m e n t t i 2 Mutta funktiolla on edelleen vain yksi parametri (mutta se saattaa palauttaa funktion, joka syö myöhempiä parametreja).

idea on nimetty loogikko Haskell B. Curryn (1900 1982) mukaan idean keksivät kuitenkin aiemmin Gottlob Frege (1848 1925) ja Moses Schönfinkel (1889 1942) huomaa vakiokirjaston funktiot curry : : ( ( a, b ) > c ) > a > b > c curry f x y = f ( x, y ) uncurry : : ( a > b > c ) > ( ( a, b ) > c ) uncurry f p = f ( f s t p ) ( snd p )

η-muunnos 1 Seuraavat funktiot f ja g ovat sama funktio. f x = (... ) x g = (... ) Esimerkkejä vakiokirjastosta: sum, product : : (Num a ) => [ a ] > a sum = f o l d l (+) 0 product = f o l d l ( ) 1 1 η on kreikkalainen kirjain eta

Kombinaattori Määritelmä: Kombinaattori on funktio, jonka kaikki parametrit ovat (ensimmäisen tai korkeamman kertaluvun) funktioita Kombinaattori yleensä palauttaa funktion Haskellissa näin ollen se, onko joku funktio kombinaattori, on yleensä käyttötavasta, ei määritelmästä, riippuvaa.

Vakiokirjaston kombinaattori: (.) (. ) : : ( b > c ) > ( a > b ) > ( a > c ) f. g = \ x > f ( g x ) Kyseessä on matematiikan pallo-operaattori eli funktioiden kompositio. Käyttöesimerkkejä vakiokirjastosta: concatmap : : ( a > [ b ] ) > [ a ] > [ b ] concatmap f = concat. map f any, a l l : : ( a > Bool ) > [ a ] > Bool any p = or. map p a l l p = and. map p

Vakiokirjaston kombinaattori: flip f l i p : : ( a > b > c ) > ( b > a > c ) f l i p f = \x y > f y x flip siis vaihtaa parametrifunktionsa kahden ekan parametrin järjestystä. Käyttöesimerkkejä vakiokirjastosta: r e v e r s e : : [ a ] > [ a ] r e v e r s e = f o l d l ( f l i p ( : ) ) [ ] s u b t r a c t : : (Num a ) => a > a > a s u b t r a c t = f l i p ( ) Muita esimerkkejä: foreachm : : [ a ] > ( a > IO b ) > IO [ b ] foreachm = f l i p mapm foreachm_ : : [ a ] > ( a > IO b ) > IO ( ) foreachm_ = f l i p mapm_

Kombinaattorikirjastoista yksi funktio-ohjelmoinnin keskeisimmistä käsitteistä on kombinaattorikirjasto kirjasto koostuu muutamasta kombinaattorista, jotka pelaavat yhteen tuloksena syntyy ns. DSL ( domain-specific language )

ParComp on kombinaattorikirjasto data P a r s e r tok sem = P a r s e r ( [ tok ] > [ ( sem, [ tok ] ) ] ) (@ ) : : P a r s e r tok a > P a r s e r tok a > P a r s e r tok a (@@) : : P a r s e r tok a > ( a > b ) > P a r s e r tok b (@>) : : P a r s e r tok a > P a r s e r tok ( a > b ) > P a r s e r tok b Parser tok sem on funktiotyyppi!... tai siis isomorfinen funktiotyypin kanssa... konkreettisesti [tok] > [(sem, [tok])] mutta myös abstraktisti: funktio tok:sta sem:iin joten (@ ), (@@) ja (@>) ovat kombinaattoreita

ParComp on DSL domain (toimintapiiri, vaikutusalue) on kontekstittomat kieliopit tyyppiä Parser tok sem oleva arvo määrittelee kielen mitkä tok-jonot kuuluvat kyseiseen kieleen mikä tyyppiä sem oleva semanttinen arvo kuhunkin sallittuunjonoon liittyy

get :: Eq tok =>tok > Parser tok tok get hyväksyy kielen, johon kuuluu yksi merkkijono sen pituus on yksi ja se koostuu annetusta päätesymbolista; ko. merkkijonon semanttinen arvo on ko. päätesymboli

getid :: Parser Token String getid hyväksyy kielen, johon kuuluu yksi merkkijono sen pituus on yksi ja se koostuu nimestä (identifier) ko. merkkijonon semanttinen arvo on ko. nimi merkkijonona

(@>) :: Parser tok a > Parser tok (a > b) > Parser tok b (@>) yhdistää kaksi jäsennintä kompositiona p @> q hyväksyy kielen, jonka kukin merkkijono alkaa jollakin p:n merkkijonolla ja jatkuu (ja päättyy) jollakin q:n merkkijonolla q:n semanttisen arvon tulee olla funktio, joka ottaa p:n semanttisen arvon parametrinaan ja palauttaa uuden semanttisen arvon p @> q:n semanttinen arvo saadaan antamalla p:n semanttinen arvo q:n semanttiselle arvolle argumenttina

(@@) :: Parser tok a > (a > b) > Parser tok b (@@) muokkaa jäsentimen semanttista arvoa iso jekku tulee siitä, että (@@):llä on korkeampi presedenssi kuin (@>):llä, joka assosioi oikealle jos f :: t1 > t2 > t3, niin b @@ f :: t2 > t3 ja b :: t1, ja a @> b @@ f :: t3 ja a :: t2 siten lausekkeessa p1 @>... @> pn @@ f funktio f saa parametrinaan jäsentimien p1,..., pn semanttiset arvot käänteisessä järjestyksessä joten f toimii (S-)attribuuttikieliopin attribuuttilausekkeena!

(@ ) :: Parser tok a > Parser tok a > Parser tok a (@ ) ottaa kahden kielen yhdisteen jokainen tok-jono, joka kuuluu p:n tai q:n määrittelemään kieleen, kuuluu myös p @ q:n määrittelemään kieleen merkkijonon semanttinen arvo pysyy samana entä jos sama merkkijono kuuluu molempiin kieliin? silloin yhdistekielessä ko. merkkijonolla on useita (mahdollisesti) eri semanttista arvoa kumpi palautetaan määräytyy hyväntahtois-epädeterministisesti (engl. angelic nondeterminism) eli ei palauteta sitä, joka aiheuttaa jäsennyksen epäonnistumisen myöhemmin, mutta palautetaan jokin muista

expr -> cmp $1 expr -> if expr then expr else expr If $2 $4 $6 expr -> let Ident = expr in expr Let $2 $4 $6 e x p r : : P a r s e r Token Expr e x p r = cmp @@ (\ s1 > s1 ) @ g e t KW_If @> e x p r @> g e t KW_Then @> e x p r @> g e t KW_Else @> e x p r @@ (\ s6 _ s4 _ s2 _ > I f s2 s4 s6 ) @ get KW_Let @> g e t I d @> get Eq @> expr @> get KW_In @> expr @@ (\ s6 _ s4 _ s2 _ > L e t s2 s4 s6 )

ParComp:n toteutus data P a r s e r tok sem = P a r s e r ( [ tok ] > [ ( sem, [ tok ] ) ] ) Parser tok sem on funktio...... joka ottaa tok-jonon...... ja palauttaa listan kaikista mahdollisista listan alkuosan jäsennyksistä: kunkin jäsennyksen semanttisen arvon ja mitä tok-jonosta jäi jäsentämättä

get n ja getid n toteutus g e t I f : : ( t o k > Maybe a ) > P a r s e r t o k a g e t I f p = P a r s e r $ \ t o k s > c a s e t o k s o f [ ] > [ ] t : t s > c a s e p t o f J u s t sem > [ ( sem, t s ) ] N o t h i n g > [ ] g e t : : Eq t o k => t o k > P a r s e r t o k t o k g e t t o k = g e t I f $ \ x > i f x==t o k t h e n J u s t x e l s e N o t h i n g g e t I d : : P a r s e r Token S t r i n g g e t I d = g e t I f t e s t I d where t e s t I d ( I d e n t x ) = J u s t x t e s t I d _ = N o t h i n g yleinen funktio getif sen parametri palauttaa Just sem, jos kohdalle osuu oikea päätesymboli (sem on palautettava semanttinen arvo), muuten Nothing

(@ ) n toteutus (@ ) : : P a r s e r tok a > P a r s e r tok a > P a r s e r tok a P a r s e r p @ P a r s e r q = P a r s e r (\ t o k s > p t o k s ++ q t o k s ) tok-listan (toks) alkuosan kaikki mahdolliset jäsennykset saadaan ottamalla yhdiste (++)

(@@) n toteutus (@@) : : P a r s e r tok a > ( a > b ) > P a r s e r tok b P a r s e r p @@ f = P a r s e r $ \ t o k s > f l i p map ( p t o k s ) $ \ ( psem, p r e s t ) > ( f psem, p r e s t ) jokaisen mahdollisen jäsennyksen semanttiseen arvoon sovelletaan annettua funktiota

(@>) n toteutus (@>) : : Parser tok a > Parser tok ( a > b ) > Parser tok b P a r s e r p @> ~( P a r s e r q ) = P a r s e r $ \ t o k s > c o n c a t $ f l i p map ( p t o k s ) $ \ ( psem, p r e s t ) > f l i p map ( q p r e s t ) $ \ ( qsem, q r e s t ) > ( qsem psem, q r e s t ) tok-jono (toks) annetaan p-jäsentimelle sen tuottamalle jokaiselle jäsennystulokselle (psem,prest): jäljellä oleva tok-jono ( prest) annetaan q-jäsentimelle se tuottaa listan jäsennystuloksia kunkin tuloksen semanttiselle arvolle (joka on funktio) sovelletaan p:n tuottamaa semanttista arvoa (psem) tästä tuloksena on lista listoja, jotka yhdistetään concat-funktioilla

~hahmo on ns. laiska hahmo eli viivästetty hahmo hahmonsovitusta ei yritetä heti, vaan sovituksen oletetaan onnistuvan hahmonsovitusta yritetään vasta, kun hahmossa määriteltyä muuttujaa ekan kerran käytetään sovituksen epäonnistuminen kaataa ohjelman joten älä käytä tällaista muuttujaa, ellet ole varma että sovitus onnistuu! (@>)-operaattorin toinen parametri on viivästetty hahmo, jotta (ei-vasen-)rekursio toimisi!

runparser r u n P a r s e r : : Show t o k => P a r s e r t o k sem > [ t o k ] > E i t h e r S t r i n g sem runparser ( Parser p ) toks = f ( undefined, toks, maxbound ) ( p toks ) where f ( r e s, _, 0) _ = R i g h t r e s f ( r e s, t s, _) [ ] = L e f t ( " p a r s e e r r o r n e a r " ++ show t s ) f ( r e s, t s, n ) ( ( sem, t s ) : r e s t ) n > m = f ( sem, t s, m) r e s t o t h e r w i s e = f ( r e s, t s, n ) r e s t where m = l e n g t h t s funktio, joka ottaa jäsentimen ja tok-jonon ja palauttaa joko virheilmoituksen tai onnistuneen jäsennyksen semanttisen arvon apufunktio f etsii sen jäsennystuloksen, jolla on lyhin häntä (jäsentämättä jäänyt loppumerkkijono) jos häntää ei ole, jäsennys onnistui jos onnistuneita jäsennyksiä oli useita, funktio valitsee yhden jos häntää oli, merkkijono ei kuulu kieleen ja virhe lienee lähellä sitä kohtaa, johon jäsennys päättyy (arvaus!)

ParComp: plussat ja miinukset + jäsennin on isomorfinen kieliopin kanssa + toimii, vaikka kielioppi olisikin moniselitteinen + ei rajoitusta lookaheadille naivi algoritmi, tehoton yksiselitteisillä kieliopeilla vaatii vasemman rekursion poiston

Kehitysideoita lasketaan joka jäsentimelle FIRST-joukot voidaan raakata pois heti ilmiselvästi toimimattomat vaihtoehdot määrittelemällä Parser-tyyppi ja kombinaattorit toisin voisi ParComp-jäsentimestä tuottaa ulos kielioppikaaviot (ns. raidekaaviot ) sopivasti määrittelemällä samalla kirjastolla voisi saada aikaan sekä jäsentimen että kaaviot

newtype käärötyypit kuten Parser käyttävät vain osaa datan ilmaisuvoimasta kääntäjän optimointeja auttaa, jos tällaiset määritellään newtype-avainsanalla: newtype P a r s e r t o k sem = P a r s e r ( [ t o k ] > [ ( sem, [ t o k ] ) ] ) newtype-tyypillä saa olla vain yksi koostin... ja ko. koostimella saa olla vain yksi argumentti pieni ero semantiikassa, johon palattaneen myöhemmin