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