From 15b5138bd04e56ceb6f1dca051a07cce5551de62 Mon Sep 17 00:00:00 2001 From: interp Date: Sun, 18 Jan 2004 03:32:08 +0000 Subject: [PATCH] Some more sections (session-data, part of mysxml) --- doc/latex/surflethowto.tex | 269 +++++++++++++++++++++++++++++++------ 1 file changed, 231 insertions(+), 38 deletions(-) diff --git a/doc/latex/surflethowto.tex b/doc/latex/surflethowto.tex index 3617495..52e55a0 100644 --- a/doc/latex/surflethowto.tex +++ b/doc/latex/surflethowto.tex @@ -73,7 +73,7 @@ surflets: directory called \name{SSAX}, to which I will refer to as \typew{\$SSAX}. - \item Unfortunately, this distribution (plt200-4.9) has a typo in + \item Unfortunately, this SSAX distribution (plt200-4.9) has a typo in the package definition for scsh. Apply the patch that comes with the \surflets distribution to get rid of this typo: \begin{itemize} @@ -231,11 +231,11 @@ just sends the HTML page and does not return and functions as the \emph{sending functions}. In a \surflet, HTML pages are represented as lists, or, to be more -precise, as SXML (S-expression based XML). The first element of a -SXML list is a symbol stating the HTML tag. The other elements of a -SXML list are the contents that are enclosed by this HTML tag. The -contents can be other SXML list, too. Here are some examples of SXML -lists and how they translate to HTML: +precise, as SXML (S-expression based XML).\label{sec:SXML} The first +element of a SXML list is a symbol stating the HTML tag. The other +elements of a SXML list are the contents that are enclosed by this +HTML tag. The contents can be other SXML list, too. Here are some +examples of SXML lists and how they translate to HTML: \newcommand{\htmltag}[1]{$\mathtt{<}$#1$\mathtt{>}$} \begin{tabbing} @@ -1094,10 +1094,10 @@ value, \eg functions or records. \end{alltt} \name{case-returned-via} has an extended syntax similar to \name{cond} -that it useful with annotated address. The arrow \name{=>} calls the -following function with the annotation of the address via which the -user has left the web page. You can extract the annotation yourself -with \name{returned-via} like this: +that it useful with annotated address. The arrow `\name{=>}' calls +the following function with the annotation of the address via which +the user has left the web page. You can extract the annotation +yourself with \name{returned-via} like this: \begin{alltt} (result-page (returned-via language bindings)) @@ -1126,7 +1126,7 @@ Several different callbacks would result in the storage of the several slightly different continuations. This is unnecessary, as you can annotate the callbacks with the arguments for the callback function. Let's see an example which is a variation of the previous examples -(important parts emphasized): +(important parts / differences emphasized): \begin{listing} (define-structure surflet surflet-interface @@ -1166,37 +1166,230 @@ first argument. Furthermore, you don't have to use callbacks. However, it can be sensible to combine the dispatch and the callback method, so you have to use \name{send-html/suspend}. +Note that is nonsensical to create a callback on top level, \ie the +call to \name{make-annotated-callback} must occur every time +\name{main} is called and not only once when the \surflet is read into +memory. For the same reason it is nonsensical in most cases to reuse +a callback. + +The \surflet library provides also a wrapper function with which you +can instruct the callback to call different functions instead of a +single one. If you create your callback like + +\begin{alltt} +(let ((callback (make-annotated-callback callback-function))) + \dots) +\end{alltt} + +you can instruct the callback to call different functions like this: + +\begin{alltt} +(callback function1 arg1 arg2) +\dots +(callback function2 arg3 arg4 arg5) +\end{alltt} + +Again, it is your choice which option you want to use. Note that +calling a function with several arguments and of different amount each +time is also possible if you only use a single function for the +callback. + +\section{Data management} + +When you write web programs, there are usually two kinds of data that +you use: data that is local to each instance of a \surflet, \eg the +users login, and data that is global to each instance of a \surflet, +\eg a port to a logfile. Changes to local data is only visible to +each instance of a \surflet, while changes to global data is visible +to every instance of a \surflet. + +The \surflet library does not really distinguish between these two +types of data, but provides ways to realize both of them in a +convenient way that is not (really) different from the way you handle +this data types in a regular Scheme program. + +If a data item is globally used in your \surflet, define it global +(on top level) and change its values with \name{set!}. If a data +item is locally used, define it locally (in your function) and do not +change its value with \name{set!}. + +If the following sounds too technical to you, you can safely skip this +paragraph. The reason why the distinction between global and local +data is done via whether you mutate the data's value with \name{set!} +is that the \surflets are implemented with continuations. +Continuations cannot reflect changes that are done via \name{set!} (or +side effects in general) and thus such changes are globally visible. +On the other hand continuations represent states of a program and a +reified continuations reifies also the values of all (local) data. + +But what to do if you happen to want to change your \emph{local} +data's value with \name{set!}? The \surflet library provides a place +where you store such mutable local data and two functions to access +it: \name{set-session-data!} sets the mutable local data and +\name{get-session-data} reads the mutable local data. Here is an +example. It uses the callback technique that was presented in the +previous section. If you haven't read that section, you only need to +know that \name{show-page} is called again and again as long as the +user keeps on clicking on ``Click''. + +\begin{listing} +(define-structure surflet surflet-interface + (open surflets + surflets/callbacks + scheme-with-scsh) + (begin + (define (main req) + (set-session-data! -1) + (let ((start (make-annotated-callback show-page))) + (show-page req 'click start))) + + (define (show-page req what callback) + (if (eq? what 'click) + (click callback) + (cancel))) + + (define (click callback) + (set-session-data! (+ 1 (get-session-data))) + (send-html + `(html + (head (title "Click counter")) + (body + (h2 "Click or cancel") + (p "You've already clicked " + ,(get-session-data) + " times.") + (p (url ,(callback 'click callback) "Click") + (url ,(callback 'cancel callback) "Cancel")))))) + + (define (cancel) + (send-html/finish + `(html + (head (title "Click counter finished")) + (body + (h2 "Finished") + (p "after " ,(get-session-data) " clicks."))))) +)) +\end{listing} + +At the beginning of \name{main} we initialize the mutable local data +with \name{set-session-data!}. + +\begin{alltt} + (define (main req) + (set-session-data! -1) + (let ((start (make-annotated-callback show-page))) + (show-page req 'click start))) +\end{alltt} + +Afterwards, we create and save a callback that will be called again +and again. We call \name{show-page} with the callback to show the +first web page. + +\begin{alltt} + (define (show-page req what callback) + (if (eq? what 'click) + (click callback) + (cancel))) +\end{alltt} + +\name{show-page} evaluates its second argument \name{what} to +determine what to do next: continue or cancel. + +\begin{alltt} + (define (click callback) + (set-session-data! (+ 1 (get-session-data))) + (send-html + `(html + (head (title "Click counter")) + (body + (h2 "Click or cancel") + (p "You've already clicked " + ,(get-session-data) + " times.") + (p (url ,(callback 'click callback) "Click") + (url ,(callback 'cancel callback) "Cancel")))))) +\end{alltt} + +If the user continues, \name{click} increases the mutable local +counter and shows the next page. + +Note that we don't use \name{send-html/suspend} here because we use +the callback to lead to the next web page. If the user clicks on the +link labeled with ``Click'' or ``Cancel'', \name{show-page} will be +called with \typew{'click} or \typew{'cancel}, respectively, and the +callback as parameters. This creates an endless loop without saving +endless states of the \surflet. + +\name{cancel} shows the final page with the amount of clicks +performed. + +\section{My own SXML} + +Section \ref{sec:SXML} introduced SXML, the way how \surflets +represent HTML. This section will show you, how you can create your +own rules to translate from SXML to HTML. + +\subsection{Terms and theoretical background} + +This subsection will introduce the main concepts of the translation +process and some necessary terms we will use in the following. + +The translation process from SXML to HTML takes two steps. In the +first step, SXML is translated to an intermediate form. This is done +by the \textit{translator}. In the second step, the intermediate form +is translated into an HTML string. This is done by the +\textit{printer}. The intermediate form looks very much like SXML, +but contains only atoms or, recursively, list of \textit{atoms}. +Atoms are numbers, characters, strings, \sharpf, and the empty list. +We call the intermediate form an \textit{atom tree} and the list from +which we've started an \textit{SXML tree}. + +The basic unit in the translation process is a \textit{conversion +rule}. A conversion rule consists of a trigger and a conversion +function. The translator calls the conversion function when it sees +the trigger at the beginning of a list in the SXML tree, \ie at a +node. It calls the conversion function with the all list elements as +parameters and replaces the whole list by the result of the conversion +function. The result of the conversion function is supposed to be an +atom tree. + +The translator gets the SXML tree and a list of conversion rules as +arguments. It then traverses the SXML tree depth first and calls the +conversion functions according to the triggers it encounters, +replacing the nodes in the SXML tree with the result of the conversion +functions it called for each node. The result of this translation +step will be an atom tree, which the printer will print to a port. + +There are exceptions to this basic rules. First, the translator might +not traverse the whole SXML tree. If the translator traverses the +whole tree, every argument to a conversion function is first +translated before it is passed to the conversion function. This is +the regular case and we say the conversion function gets its arguments +\textit{preprocessed}. However, the conversion rule can instruct the +translator not to preprocess the conversion function's arguments and +pass the arguments as they are in the SXML tree, \ie +\textit{unprocessed}. In that case, the translator will stop +traversing the SXML tree at that node and replacing the whole node by +the result of the conversion function called for this node. + +Second, there are two default triggers which you can't use in your +translation rules: \typew{*default*} and \typew{*text*}. The +conversion rule that uses \typew{*default*} as its trigger is the +default conversion rule which the translator uses if no other +conversion rule triggers for a node in the SXML tree. The conversion +rule that uses \typew{*text*} as its trigger is the text conversion +rule and triggers, if the node in the SXML tree is a string. In the +standard conversion rule set the text conversion rule performs HTML +escaping, \eg for the ampersand (\&). + + \section{Outlook} -More to come soon about data management, \surflets containing of -different parts and individual SXML. +More to come soon about\surflets containing of different parts and +individual SXML. + -%\section{Data management} -% -%There are different kinds of data that float around in a \surflet, -%actually in any serve side scripted program: There is local data that -%is associated to each session, \ie each session has its own copy of -%this data and if one session modifies this data it does not change the -%value of the data in other sessions. There is also global data, \ie -%data that is shared among sessions and modification of this data in -%one session is visible in other sessions. Both types of data are -%realizable in a \surflet. -% -%Local data is managed automatically by the \surflet library. When you -%call \name{send-html/suspend}, your local data is saved in a -%continuation. After the user has proceeded in your web site, this -%continuation and thus your local data is restored. -% -%As all data is stored in a continuation, there are no copies of your -%data saved. This means that if you change data via side effects, \eg -%via \name{set!}, this changes remain effective after the continuation -%has been restored. Thus, using side effects to change data, for -%example with \name{set!} is a way to realize global data. -% -%Sometimes it is desirable to be able to change local data via side -%effects. -% %\end{document} %session data