<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>