📄 tut.html
字号:
<p><pre><code>: (commit) # Commit all changes-> T: (bye) # Exit picolisp$ # back to the shell</code></pre><p>So, the next time when ..<p><pre><code>$ ./p dbg.l # .. we start Pico Lisp: (pool "test.db") # and open the database file,-> T: (show *DB) # our two symbols are there again{1} "Hello world" newSym {2} b 2 a 1-> {1}: (show *DB 'newSym){2} NIL x 777-> {2}</code></pre><p><hr><h2><a name="db">Database Programming</a></h2><p>To a database, there is more than just persistence. Pico Lisp includes anentity/relation class framework (see also <a href="ref.html#dbase">Database</a>)which allows a close mapping of the application data structure to the database.<p>We provided a simple yet complete database and GUI demo application in<code><a href="family.l">doc/family.l</a></code>. We recommend to start it upfor test purposes in the following way:<p><pre><code>$ ./p dbg.l doc/family.l -main:</code></pre><p>This loads the source file, initializes the database by calling the<code>main</code> function, and prompts for user input.<p>The data model is small and simple. We define a class <code>+Person</code>and two subclasses <code>+Man</code> and <code>+Woman</code>.<p><pre><code>(class +Person +Entity)</code></pre><p><code>+Person</code> is a subclass of the <code>+Entity</code> system class.Usually all objects in a database are of a direct or indirect subclass of<code>+Entity</code>. We can then define the relations to other data with the<code><a href="refR.html#rel">rel</a></code> function.<p><pre><code>(rel nm (+Need +Sn +Idx +String)) # Name</code></pre><p>This defines the name property (<code>nm</code>) of a person. The firstargument to <code>rel</code> is always a list of relation classes (subclasses of<code>+Relation</code>), optionally followed by further arguments, causingrelation daemon objects be created and stored in the class definition. Thesedaemon objects control the entity's behavior later at runtime.<p>Relation daemons are a kind of <i>metadata</i>, controlling the interactionsbetween entities, and maintaining database integrity. Like other classes,relation classes can be extended and refined, and in combination with properprefix classes a fine-grained description of the application's structure can beproduced.<p>Besides primitive relation classes, like <code>+Number</code>,<code>+String</code> or <code>+Date</code>, there are<ul><li>relations between entities, like <code>+Link</code> (unidirectional link),<code>+Joint</code> (bidirectional link) or <code>+Hook</code> (object-localindex trees)<li>relations that bundle other relations into a single unit (<code>+Bag</code>)<li>a <code>+List</code> prefix class<li>a <code>+Blob</code> class for "binary large objects"<li>prefix classes that maintain index trees, like <code>+Key</code> (uniqueindex), <code>+Ref</code> (non-unique index) or <code>+Idx</code> (full textindex)<li>prefix classes which in turn modify index class behavior, like<code>+Sn</code> (soundex algorithm [<a href="#knuth73">knuth73</a>] fortolerant searches)<li>a <code>+Need</code> prefix class, for existence checks<li>a <code>+Dep</code> prefix class controlling dependencies between otherrelations</ul><p>In the case of the person's name (<code>nm</code>) above, the relation objectis of type <code>(+Need +Sn +Idx +String)</code>. Thus, the name of each personin this demo database is a mandatory attribute (<code>+Need</code>), searchablewith the soundex algorithm (<code>+Sn</code>) and a full index(<code>+Idx</code>) of type <code>+String</code>.<p><pre><code>(rel pa (+Joint) kids (+Man)) # Father(rel ma (+Joint) kids (+Woman)) # Mother(rel mate (+Joint) mate (+Person)) # Partner</code></pre><p>The attributes for <i>father</i> (<code>pa</code>), <i>Mother</i>(<code>ma</code>) and <i>partner</i> (<code>mate</code>) are all defined as<code>+Joint</code>s. A <code>+Joint</code> is probably the most powerfulrelation mechanism in Pico Lisp; it establishes a bidirectional link betweentwo objects.<p>The above declarations say that the <i>father</i> (<code>pa</code>) attributepoints to an object of type <code>+Man</code>, and is joined with that object's<code>kids</code> attribute (which is a list of joints back to all hischildren).<p>The consistency of <code>+Joint</code>s is maintained automatically by therelation daemons. These become active whenever a value is stored to a person's<code>pa</code>, <code>ma</code>, <code>mate</code> or <code>kids</code>property.<p>For example, interesting things happen when a person's <code>mate</code> ischanged to a new value. Then the <code>mate</code> property of the old mate'sobject is cleared (she has no mate after that). Now when the person pointed toby the new value already has a mate, then that mate's <code>mate</code> propertygets cleared, and the happy new two mates now get their joints both setcorrectly.<p>The programmer doesn't have to care about all that. He just declares theserelations as <code>+Joint</code>s.<p>The last four attributes of person objects are just static data:<p><pre><code>(rel job (+Ref +String)) # Occupation(rel dat (+Ref +Date)) # Date of birth(rel fin (+Ref +Date)) # Date of death(rel txt (+String)) # Info</code></pre><p>They are all searchable via a non-unique index (<code>+Ref</code>). Datevalues in Pico Lisp are just numbers, representing the numbers of days sincefirst of March in the year zero.<p>A method <code>url></code> is defined:<p><pre><code>(dm url> () (list "@person" '*ID This) )</code></pre><p>It is needed later in the GUI, to cause a click on a link to switch to thatobject.<p>The classes <code>+Man</code> and <code>+Woman</code> are subclasses of<code>+Person</code>:<p><pre><code>(class +Man +Person)(rel kids (+List +Joint) pa (+Person)) # Children(class +Woman +Person)(rel kids (+List +Joint) ma (+Person)) # Children</code></pre><p>They inherit everything from <code>+Person</code>, except for the<code>kids</code> attribute. This attribute joins with the <code>pa</code> or<code>ma</code> attribute of the child, depending on the parent's gender.<p>That's the whole data model for our demo database application.<p>It is followed by a call to <code>dbs</code> ("database sizes"). This call isoptional. If it is not present, the whole database will reside in a single file,with a block size of 256 bytes. If it is given, it should specify a list ofitems, each having a number in its CAR, and a list in its CDR. The CARs takentogether will be passed later to <a href="refP.html#pool">pool</a>, causing anindividual database file with that size to be created. The CDRs tell what entityclasses (if an item is a symbol) or index trees (if an item is a list with aclass in its CAR and a list of relations in its CDR) should be placed into thatfile.<p>A handful of access functions is provided, that know about databaserelationships and thus allows higher-level access modes to the external symbolsin a database.<p>For one thing, the B-Trees created and maintained by the index daemons can beused directly. Though this is rarely done in a typical application, they formthe base mechanisms of other access modes and should be understood first.<p>The function <code>tree</code> returns the tree structure for a givenrelation. To iterate over the whole tree, the functions <code>iter</code> and<code>scan</code> can be used:<p><pre><code>(iter (tree 'dat '+Person) '((P) (println (datStr (get P 'dat)) (get P 'nm))))"1770-08-03" "Friedrich Wilhelm III""1776-03-10" "Luise Augusta of Mecklenburg-Strelitz""1797-03-22" "Wilhelm I"...</code></pre><p>They take a function as the first argument. It will be applied to all objectsfound in the tree (to show only a part of the tree, an optional begin- andend-value can be supplied), producing a simple kind of report.<p>More useful is <code>collect</code>; it returns a list of all objects thatfall into a range of index values:<p><pre><code>: (collect 'dat '+Person (date 1982 1 1) (date 1988 12 31))-> ({2-M} {2-L} {2-E})</code></pre><p>This returns all persons born between 1982 and 1988. Let's look at them with<code>show</code>:<p><pre><code>: (more (collect 'dat '+Person (date 1982 1 1) (date 1988 12 31)) show){2-M} (+Man) nm William dat 724023 ma {2-K} pa {2-J} job Heir to the throne{2-L} (+Man) nm Henry dat 724840 ma {2-K} pa {2-J} job Prince{2-E} (+Woman) nm Beatrice dat 726263 ma {2-D} job Princess pa {2-B}</code></pre><p>If you are only interested in a certain attribute, e.g. the name, you canreturn it directly:<p><pre><code>: (collect 'dat '+Person (date 1982 1 1) (date 1988 12 31) 'nm)-> ("William" "Henry" "Beatrice")</code></pre><p>To find a single object in the database, the function <code>db</code> isused:<p><pre><code>: (db 'nm '+Person "Edward")-> {2-;}</code></pre><p>If the key is not unique, additional arguments may be supplied:<p><pre><code>: (db 'nm '+Person "Edward" 'job "Prince" 'dat (date 1964 3 10))-> {2-;}</code></pre><p>The programmer must know which combination of keys will suffice to specifythe object uniquely. The tree search is performed using the first value("Edward"), while all other attributes are used for filtering. Later, inthe <a href="#pilog">Pilog</a> section, we will show how more general (andpossibly more efficient) searches can be performed.<p><hr><h2><a name="gui">User Interface (GUI) Programming</a></h2><p>The only types of GUI supported by the Pico Lisp application server frameworkis either dynamically generated (but static by nature) HTML, or an interactiveXHTML/CSS framework with the optional use of JavaScript.<p>Before we explain the GUI of our demo database application, we present aminimal example for a plain HTML-GUI in <code><ahref="hello.l">doc/hello.l</a></code>. Start the application server as:<p><pre><code>$ ./p lib/http.l -'server 8080 "doc/hello.l"' -wait</code></pre><p>Now point your browser to the address '<code><ahref="http://localhost:8080">http://localhost:8080</a></code>'. You should see avery simple HTML page. You can come back here with normal browser navigation, orwith the '<code><<<</code>' link in the upper right corner.<p>You can call the page repeatedly, or concurrently with many clients if youlike. To terminate the server, you have to send it a TERM signal (e.g.'<code>killall picolisp</code>'), or type the <code>Ctrl-C</code> key in theconsole window.<p>In our demo database application, a single function <code>person</code> isresponsible for the whole GUI. Again, please look at <code><ahref="family.l">doc/family.l</a></code>.<p>To start the database <i>and</i> the application server, call:<p><pre><code>$ ./p dbg.l doc/family.l -main -go</code></pre><p>As before, the database is opened with <code>main</code>. The function<code>go</code> is also defined in <code>doc/family.l</code>:<p><pre><code>(de go () (server 8080 "@person") )</code></pre><p>It starts the HTTP server listening on TCP port 8080 (we did a similar thingin our minimal GUI example above directly on the command line). Each connect tothat port will cause the function <code>person</code> to be invoked.<p>Again, point your browser to the address '<code><ahref="http://localhost:8080" target="GUI">http://localhost:8080</a></code>'.<p>You should see a new browser window with an input form created by thefunction <code>person</code>. We provided an initial database in"doc/family[1-4]". You can navigate through it by clicking on the pencil iconsbesides the input fields.<p>The chart with the children data can be scrolled using the down(<code>v</code>) and up (<code>^</code>) buttons.<p>A click on the button "Select" below opens a search dialog. You can scrollthrough the chart as before. Again, a click on a pencil will jump to thatperson. You can abort the dialog with a click on the "Cancel"-button.<p>The search fields in the upper part of the dialog allow a conjunctive search.If you enter "Edward" in the "Name" field and click "Search", you'll see allpersons having the string "Edward" in their name. If you also enter "Duke" inthe "Occupation" field, the result list will reduce to only two entries.<p>To create a new person, press the "New Man" or "New Woman" button. A newempty form will be displayed. Please type a name into the first field, andperhaps also an occupation and birth date. Any change of contents should befollowed by a press on the "Save" button, though any other button (also Scrollor Select-buttons) will also do.<p>To assign a <i>father</i> attribute, you can either type a name directly intothe field (if that person already exists in the database and you know the exactspelling), or use the "Set"-button (<code>-></code>) to the left of thatfield to open the search dialog. If you type in the name directly, your inputmust exactly match upper and lower case.<p>Alternatively, you may create a new person and assign a child in the"Children" chart.<p>On the console where you started Pico Lisp, there should a prompt haveappeared just when the browser connected. You can debug the applicationinteractively while it is running. For example, the global variable<code>*Top</code> always contains the top level GUI object:<p><pre><code>: (show *Top)</code></pre><p>To take a look at the first field on the form:<p><pre><code>: (show *Top 'gui 1)</code></pre><p>A production application would be started in a slightly different way:<p><pre><code>$ ./p doc/family.l -main -go -wait</code></pre><p>In that case, no debug prompt will appear. In both cases, however, two<code>picolisp</code> processes will be running now. One is the initial serverprocess which will continue to run until it is killed. The other is a childprocess holding the state of th
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -