<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; " class=""><div class=""><div class="">Hello,</div><div class=""><br class=""></div><div class=""><div class="">After much scratching of my head over intricate parts of this "Haskell" thing</div><div class="">I'm happy to announce that I've finally released my first effort in it: HaskRel.</div></div><div class=""><br class=""></div><div class=""><div class="">Overview</div><div class="">--------</div></div><div class=""><br class=""></div><div class=""><div class=""><div class="">Because I've spent quite a bit of time on database prompts I thought it would be</div><div class="">a fun exercise to see how much GHC can be made to operate like a DBMS, and how</div><div class="">much of the relational model of database management (as defined by Chris Date et</div><div class="">al. today) I'm able to make it accommodate. I'm pleased to register that the</div><div class="">relational algebra, base variables and assignment works as one would expect at a</div><div class="">database prompt. It does not qualify as an actual <i>RDBMS</i> (unsurprisingly),</div><div class="">since it doesn't implement many other things that are required for it to be a</div><div class="">proper RDBMS, either because I haven't gotten around to it or they cannot be</div><div class="">implemented in Haskell.</div></div></div><div class=""><br class=""></div><div class="">I've put the source up on GitHub and published it on Hackage:</div><div class=""><br class=""></div><div class=""> Hackage:</div><div class=""> <a href="http://hackage.haskell.org/package/HaskRel">http://hackage.haskell.org/package/HaskRel</a></div><div class=""><br class=""></div><div class=""> GitHub:</div><div class=""> <a href="https://github.com/thormick/HaskRel/tree/master/HaskRel">https://github.com/thormick/HaskRel/tree/master/HaskRel</a></div><div class=""><br class=""></div><div class=""><div class=""><div class="">HaskRel employs a Data.Set of Data.HList.Record as a relation type, for which it</div><div class="">defines "Relation" as a synonym. It supports base variables (files) of this</div><div class="">type, and implements the functions of the relational algebra such that they can</div><div class="">be expressed upon both constants or literal values, upon variables, and upon</div><div class="">expressions on variables.</div></div></div><div class=""><br class=""></div><div class="">Example</div><div class="">-------</div><div class=""><br class=""></div><div class=""><div class="">The following is a minimal definition of a database with a single relation</div><div class="">variable, "sp":</div></div><div class=""><br class=""></div><div class=""><span style="font-family: 'Courier New'; " class="">module MiniDB where</span></div><div class=""><font face="Courier New" class=""><br class=""></font></div><div class=""><font face="Courier New" class="">import Data.HList.CommonMain</font></div><div class=""><font face="Courier New" class="">import Database.HaskRel.RDBMS</font></div><div class=""><br class=""></div><div class=""><span style="font-family: 'Courier New'; " class="">sp :: Relvar '[Attr "sno" String,</span></div><div class=""><font face="Courier New" class=""> Attr "pno" String,</font></div><div class=""><font face="Courier New" class=""> Attr "qty" Integer]</font></div><div class=""><font face="Courier New" class="">sp = Relvar "SP.rv"</font></div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><div class="">"Attr" has been defined as a synonym for "Data.Tagged.Tagged", because that is</div><div class="">employed to represent what are known as attributes in relational theory. Loading</div><div class="">this in GHCi we can first create a relation constant, do some relational</div><div class="">assignment, and print the results (pardon the long lines):</div></div><div class=""><br class=""></div><div class=""><font face="Courier New" class="">*MiniDB> let s = ( relation' [ ( "S1", "Smith", 20, "London" ), ( "S2", "Jones", 10, "Paris" ), ( "S3", "Blake", 30, "Paris" ) ] :: Relation '[Attr "sno" String, Attr "sName" String, Attr "status" Integer, Attr "city" String] )</font></div><div class=""><span style="font-family: 'Courier New'; " class="">*MiniDB> pt s</span></div><div class=""><font face="Courier New" class="">┌───────────────┬─────────────────┬───────────────────┬────────────────┐</font></div><div class=""><font face="Courier New" class="">│ sno :: String │ sName :: String │ status :: Integer │ city :: String │</font></div><div class=""><font face="Courier New" class="">╞═══════════════╪═════════════════╪═══════════════════╪════════════════╡</font></div><div class=""><font face="Courier New" class="">│ S1 │ Smith │ 20 │ London │</font></div><div class=""><font face="Courier New" class="">│ S2 │ Jones │ 10 │ Paris │</font></div><div class=""><font face="Courier New" class="">│ S3 │ Blake │ 30 │ Paris │</font></div><div class=""><font face="Courier New" class="">└───────────────┴─────────────────┴───────────────────┴────────────────┘</font></div><div class=""><font face="Courier New" class="">*MiniDB> sp `assign` ( relation' [ ("S1", "P1", 300), ("S1", "P3", 400), ("S1", "P5", 100), ("S2", "P1", 300), ("S3", "P2", 200) ] :: Relation '[Attr "sno" String, Attr "pno" String, Attr "qty" Integer] )</font></div><div class=""><font face="Courier New" class="">Value assigned to ./SP.rv</font></div><div class=""><font face="Courier New" class="">*MiniDB> pt sp</font></div><div class=""><font face="Courier New" class="">┌───────────────┬───────────────┬────────────────┐</font></div><div class=""><font face="Courier New" class="">│ sno :: String │ pno :: String │ qty :: Integer │</font></div><div class=""><font face="Courier New" class="">╞═══════════════╪═══════════════╪════════════════╡</font></div><div class=""><font face="Courier New" class="">│ S1 │ P1 │ 300 │</font></div><div class=""><font face="Courier New" class="">│ S1 │ P3 │ 400 │</font></div><div class=""><font face="Courier New" class="">│ S1 │ P5 │ 100 │</font></div><div class=""><font face="Courier New" class="">│ S2 │ P1 │ 300 │</font></div><div class=""><font face="Courier New" class="">│ S3 │ P2 │ 200 │</font></div><div class=""><font face="Courier New" class="">└───────────────┴───────────────┴────────────────┘</font></div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><div class=""><div class=""><div class="">(Mind that correct display of the Unicode table drawing characters depends on</div><div class="">using the right fixed-width font.)</div><div><br></div></div></div></div><div class="">Fundamental operations of the relational algebra can of course be performed on</div><div class="">them:</div><div class=""><br class=""></div><div class=""><font face="Courier New" class="">*MiniDB> p $ s `naturalJoin` sp</font></div><div class=""><font face="Courier New" class="">┌─────┬───────┬────────┬────────┬─────┬─────┐</font></div><div class=""><font face="Courier New" class="">│ sno │ sName │ status │ city │ pno │ qty │</font></div><div class=""><font face="Courier New" class="">╞═════╪═══════╪════════╪════════╪═════╪═════╡</font></div><div class=""><font face="Courier New" class="">│ S1 │ Smith │ 20 │ London │ P1 │ 300 │</font></div><div class=""><font face="Courier New" class="">│ S1 │ Smith │ 20 │ London │ P3 │ 400 │</font></div><div class=""><font face="Courier New" class="">│ S1 │ Smith │ 20 │ London │ P5 │ 100 │</font></div><div class=""><font face="Courier New" class="">│ S2 │ Jones │ 10 │ Paris │ P1 │ 300 │</font></div><div class=""><font face="Courier New" class="">│ S3 │ Blake │ 30 │ Paris │ P2 │ 200 │</font></div><div class=""><font face="Courier New" class="">└─────┴───────┴────────┴────────┴─────┴─────┘</font></div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><div class=""><div class="">A proper relational database management system (which, again, this isn't, for</div><div class="">several other reasons) must support type inference for relational expressions</div><div class="">(see The Third Manifesto, relational model prescription 18). Fortunately, that</div><div class="">is of course no problem for GHC with the right extensions:</div><div><br></div></div></div><div class=""><font face="Courier New" class="">*MiniDB> :t s</font></div><div class=""><font face="Courier New" class="">s :: Relation</font></div><div class=""><font face="Courier New" class=""> '[Attr "sno" String, Attr "sName" String, Attr "status" Integer,</font></div><div class=""><font face="Courier New" class=""> Attr "city" String]</font></div><div class=""><font face="Courier New" class="">*MiniDB> :t sp</font></div><div class=""><font face="Courier New" class="">sp</font></div><div class=""><font face="Courier New" class=""> :: Relvar</font></div><div class=""><font face="Courier New" class=""> '[Attr "sno" String, Attr "pno" String, Attr "qty" Integer]</font></div><div class=""><font face="Courier New" class="">*MiniDB> :t s `naturalJoin` sp</font></div><div class=""><font face="Courier New" class="">s `naturalJoin` sp</font></div><div class=""><font face="Courier New" class=""> :: IO</font></div><div class=""><font face="Courier New" class=""> (containers-0.5.6.2:Data.Set.Base.Set</font></div><div class=""><font face="Courier New" class=""> (RTuple</font></div><div class=""><font face="Courier New" class=""> '[Tagged "sno" String, Tagged "sName" String,</font></div><div class=""><font face="Courier New" class=""> Tagged "status" Integer, Tagged "city" String, Tagged "pno" [Char],</font></div><div class=""><font face="Courier New" class=""> Tagged "qty" Integer]))</font></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">DML is also supported, of course:</div><div class=""><br class=""></div><div class=""><font face="Courier New" class="">*MiniDB> insert sp ( relation' [ ("S1", "P2", 200), ("S1", "P3", 400), ("S1", "P4", 200) ] :: Relation '[Attr "sno" String, Attr "pno" String, Attr "qty" Integer] )</font></div><div class=""><font face="Courier New" class="">Inserted 2 of 3 tuples into ./SP.rv</font></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">Concise expression of "update" require a set of language extensions (this in</div><div class="">addition to DataKinds, which this module enables by default since it is quite</div><div class="">ubiquitous in this endeavor):</div><div class=""><br class=""></div><div class=""><font face="Courier New" class="">*MiniDB> :set -XQuasiQuotes -XKindSignatures -XViewPatterns</font></div><div class=""><font face="Courier New" class="">*MiniDB> :{</font></div><div class=""><font face="Courier New" class="">*MiniDB| update sp (\[pun|pno qty|] -> ( pno == "P2" || pno == "P3" || pno == "P4" ) && qty < 300 )</font></div><div class=""><font face="Courier New" class="">*MiniDB| (\[pun|qty|] -> case qty + 50 of qty -> [pun|qty|])</font></div><div class=""><font face="Courier New" class="">*MiniDB| :}</font></div><div class=""><font face="Courier New" class="">Updated 3 of 7 tuples in ./SP.rv</font></div><div class=""><font face="Courier New" class="">*MiniDB> pt$ sp `restrict` \[pun|pno|] -> ( pno == "P2" || pno == "P3" || pno == "P4" )</font></div><div class=""><font face="Courier New" class="">┌───────────────┬───────────────┬────────────────┐</font></div><div class=""><font face="Courier New" class="">│ sno :: String │ pno :: String │ qty :: Integer │</font></div><div class=""><font face="Courier New" class="">╞═══════════════╪═══════════════╪════════════════╡</font></div><div class=""><font face="Courier New" class="">│ S1 │ P2 │ 250 │</font></div><div class=""><font face="Courier New" class="">│ S1 │ P3 │ 400 │</font></div><div class=""><font face="Courier New" class="">│ S1 │ P4 │ 250 │</font></div><div class=""><font face="Courier New" class="">│ S3 │ P2 │ 250 │</font></div><div class=""><font face="Courier New" class="">└───────────────┴───────────────┴────────────────┘</font></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">And of course delete-by-predicate:</div><div class=""><br class=""></div><div class=""><div class=""><font face="Courier New" class="">*MiniDB> count sp</font></div><div class=""><font face="Courier New" class="">7</font></div><div class=""><font face="Courier New" class="">*MiniDB> deleteP sp (\[pun|pno|] -> pno == "P3")</font></div><div class=""><font face="Courier New" class="">Deleted 1 tuples from SP.rv</font></div><div class=""><font face="Courier New" class="">*MiniDB> count sp</font></div><div class=""><font face="Courier New" class="">6</font></div></div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><div class="">For an overview of the functions of the relational algebra and relational</div><div class="">assignment defined by HaskRel see:</div></div><div class=""><br class=""></div><div class=""><a href="http://hackage.haskell.org/package/HaskRel/docs/Database-HaskRel-Relational-Expression.html">http://hackage.haskell.org/package/HaskRel/docs/Database-HaskRel-Relational-Expression.html</a></div><div class=""><br class=""></div><div class=""><div class=""><div class=""><div class="">Summary</div><div class="">-------</div><div><br></div></div></div></div><div class="">This is a personal, spare-time project, the motivations for which have been to</div><div class="">learn Haskell, and see how much of the relational model Haskell/GHC can</div><div class="">accommodate, or how much like an RDBMS GHC can operate. Making this practically</div><div class="">usable has not been part of the scope.</div><div class=""><br class=""></div><div class=""><div class="">Ascertaining that Haskell/GHC accommodates the relational algebra, relational</div><div class="">base variables and operations thereupon in such a straight forward manner, was</div><div class="">quite nice. It was particularly fun to see how this allowed examples of</div><div class="">expressions in Tutorial D from Chris Date's "SQL and Relational Theory, 2nd. ed"</div><div class="">to be expressed in Haskell in a manner quite verbatim to the originals (see</div><div class=""><a href="https://github.com/thormick/HaskRel/blob/master/HaskRel/examples/SuppliersPartsExample.hs">https://github.com/thormick/HaskRel/blob/master/HaskRel/examples/SuppliersPartsExample.hs</a></div><div class=""><div class="">and chapters 6 and 7 of said book). It was also interesting to see trivial</div><div class=""><div class="">querying and DML operations on GHCi operate in a manner similar to what one</div><div class="">would expect in a DBMS.</div></div></div></div><div class=""><br class=""></div><div class=""><div class="">Even if this isn't of practical use I still hope it is of some interest, or at</div><div class="">least that it can enable Haskell as a demonstrator of some parts of the</div><div class="">relational model for database management.</div></div><div class=""><br class=""></div><div class="">Thanks,</div><div class="">Thor Michael Støre</div></div><div class=""><br class=""></div></body></html>