Tyyppiluokat II konstruktoriluokat, funktionaaliset riippuvuudet TIES341 Funktio-ohjelmointi 2 Kevät 2006
Alkuperäislähteitä Philip Wadler & Stephen Blott: How to make ad-hoc polymorphism less ad-hoc, Proceedings of the 16th ACM SIGPLAN-SIGACT symposium on Principles of programming languages, ACM, 1989 Mark P. Jones: A system of constructor classes: overloading and implicit higher-order polymorphism, Proceedings of the conference on Functional programming languages and computer architecture, ACM, 1993 Simon Peyton Jones & Mark Jones & Erik Meijer: Type classes: an exploration of the design space, Proceedings of the Haskell Workshop, Amsterdam, The Netherlands, June 6, 1997. http://www.cse.ogi.edu/~mpj/pubs/multi.html Mark P. Jones: Type classes with Functional Dependencies, Programming Languages and Systems: 9th European Symposium on Programming, ESOP 2000. Lecture Notes in Computer Science 1782, Springer 2000.
Mapin ongelma map :: (a -> b) -> [a] -> [b] Data.Map.map :: (a -> b) -> Data.Map.Map k a -> Data.Map.Map k b yhteistä: sovella tätä funktiota tämän tietorakenteen kaikkiin alkioihin Voisiko nämä kaksi samankaltaista funktiota olla samannimisiä (niin, että voitaisiin kirjoittaa yleiskäyttöisiä funktioita, jotka käyttävät tilanteesta riippuen jompaa kumpaa)?
Tyyppiluokista ratkaisu? class Mappable m where map :: (a -> b) ->??? Edellisen luennon tyyppiluokat olisivat kiva ratkaisu, jos se onnistuisi Mitä ylläolevaan tulee???:n paikalle? m -> m? Ei oikein m a -> m b? joo, mutta mikä ihme m tässä on? ei ainakaan tyyppimuuttuja? tyyppikoostinmuuttuja?
Konstruktoriluokat (1) Tyyppiluokkien yleistys nykyisin tosin termi tyyppiluokka sisältää tämänkin Sallitaan, että tyyppimuuttuja voi edustaa paitsi tyyppiä myös tyyppikoostinta tarvitaan tyyppien tyypit, englanniksi kinds tyyppimuuttuja, joka edustaa tyyppiä, on kindiltään * tyyppimuuttuja, joka tarvitsee yhden tyyppiparametrin, on kindiltään * -> *... jne myös tyyppilausekkeella (esim. m a tai Maybe Int) on oma kindinsä tyyppilauseke on tyyppi, jos sen kind on *
Konstruktoriluokat (2) Konstruktoriluokka on muuten kuin tavallinen tyyppiluokka mutta sen tyyppimuuttuja voi olla minkä kindinen tahansa mutta tuon kindin pitää olla yksikäsitteinen, ts. sitä ei voi käyttää samassa luokassa esim. sekä tyyppinä että yksiparametrisena tyyppikoostimena instance-määrittelyssä tyyppimuuttujan paikalle laitetaan samankindinen tyyppilauseke
Vakiokirjaston tyyppiluokka: Functor class Functor f where fmap :: (a -> b) -> f a -> f b instance Functor Maybe where fmap f (Just a) = Just (f a) fmap f Nothing = Nothing instance Functor [] where fmap = map
Vakiokirjaston tyyppiluokka: Monad (1) class Monad m where return :: a -> m a fail :: String -> m a (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b p >> q = p >>= \_ -> q fail s = error s
Vakiokirjaston tyyppiluokka: Monad (2) instance Monad [] where return a = [a] xs >>= f = concatmap f xs instance Monad Maybe where return a = Just a fail _ = Nothing Just a >>= f = f a Nothing >>= _ = Nothing instance Monad IO where...
Vakiokirjaston tyyppiluokka: Monad (3) do pat <- e rest ==> e >>= \pat -> do rest do e rest ==> e >> do rest do let pat = e rest ==> let pat = e in do rest do on oikeasti vain syntaktista sokeria tämä muunnos on hyödyllinen malli, mutta ei aivan totuudenmukainen monadeista tarkemmin myöhemmin
Ongelma: säilötyyppiluokka Miten tyyppiluokilla ilmaista säilön (container) rajapinta? class Container s where empty :: s a insert :: a -> s a -> s a member :: a -> s a -> Bool OK, mutta voiko tyyppi a -> Bool kuulua tähän konstruktoriluokkaan? Ei voi, sillä siitä ei ole sopivaa * -> * -kindattua versiota.
Moniparametrityyppiluokat (1) Yleistetään vähän vielä: sallitaan tyyppiluokalle useampi tyyppiparametri nyt tyyppiluokka ei ole (välttämättä) tyyppien joukko, vaan se voi myös olla tyyppien välinen relaatio class Collection e ce where empty :: ce insert :: e -> ce -> ce lookup :: e -> ce -> Bool
Moniparametrityyppiluokat (2) Liian yleinen keinovara empty ei ole laillinen, sillä sen tyypissä ei esiinny molemmat tyyppimuuttujat Mikä on seuraavien tyyppi? f x y coll = insert x (insert y coll) g coll = f True 'a' coll Vastaus: f :: (Collection a c, Collects b c) => a -> b -> c -> c g :: (Collection Bool c, Collection Char c) => c -> c f:n tyyppi on liian yleinen! (a:n ja b:n pitäisi olla samat!)
Funktionaaliset riippuvuudet (1) Tyyppiluokan Collection e ec ensimmäinen parametri on oikeasti toisen parametrin funktio! e on säilön sisältämän datan tyyppi tieto siitä sisältyy aina säilötyyppiin ec itseensä esim. Collection Int [Int] Ilmaistaan tämä riippuvuus eksplisiittisesti: class Collection e ec ec -> e where... lue: Collection on tyyppimaailmassa elävä (osittais)funktio, joka yhdistää tyypin ec tyyppiin e
Funktionaaliset riippuvuudet (2) Yleisesti: moniparametrityyppiluokan esittelyssä voidaan määritellä parametrien välisiä riippuvuuksia: class C tyyppimuuttujia riippuvuudet where... riippuvuudet ovat muotoa tyyppimuuttujia -> tyyppimuuttujia oikealla puolella olevat tyyppimuuttujakokoelma on vasemmalla puolella olevan tyyppimuuttujakokoelman funktio
lineaarialgebraa... Esimerkki
Lopuksi Ensi tiistaina ei ole luentoa Luennoija istuu käräjiä :)