Abstract. This is a chapter that is indented to introduce the most fundamental aspects of LAML. It is part of the overall elucidative tutorial of the LAML software package. |
![]() ![]() ![]() 1 Introduction We will here assume that you sucessfully have downloaded and installed LAML on your computer. Now it is time to use it. It will be good for you if you already have some Scheme experience, but it is also possible to learn Scheme while you go along. There are many ways to do so. We have developed a web-based material about functional programming with Scheme which you may consider. Please notice that you can navigate from a Scheme program to a relevant place in the Scheme report, by clicking on the bold face keywords or the (slightly) brown procedure/function names. You can also navigate to LAML manual pages by clicking on the (slighty) dark green procedure/function names. Such names appear both the documentation and the programs. Also notice that all the circle shaped color marks - called source markers - can be navigated. Try out the elucidative navigation possibilities right away! Do also consider to look in the help page of the Scheme Elucidator (by clicking the red question mark icons in the top banner of the window). |
![]() ![]() ![]() 2 Factorial pages We start with a couple of versions of a simple web page which shows a table of factorial numbers. |
2.1 A factorial page 2.2 Another factorial page |
![]() ![]() ![]() 2.1 A factorial page |
1!, 2!, 3!, ...,Please take a look at the fac-1 page (click on the red name to see the program) which corresponds directly to the fac-1 document in the 'getting started' examples.You should also take a look at the page which is generated by the program.
The first line loads "laml.scm" from your LAML installation. The value of laml-dir is transferred from the context (by a shell script, by Emacs, or by other means) and it is bound at LAML installation time. The value of laml-dir is the directory path to your LAML installation.
The second line uses a LAML style simple-html4.01-transitional-validating. In this case we are using a style that allows us to use the HTML4.01 transitional mirror functions. The use of this style takes responsibility to load the relevant libraries. As we will see later, other LAML styles are more substantial, in the sense that they offer more than just function that supports HTML counterparts. Such more substantial document style generates HTML contents based on high level specifications at the level of XML.
Next follows the recursive factorial function fac.
The middle big part of the example shows a call to write-html. ((You can click on the name to see its SchemeDoc interface documetation). The write-html procedure comes from the laml.scm library, and it renders and writes a HTML fragment onto some file. If no file name is passed, it writes the file on fac-1.html, because the proper source name of the example is fac-1. This is a common behavior of many LAML programs. The first parameter '(raw prolog) is a list of properties; Here we ask for raw writting of the HTML fragment. We also ask for the generation of a document prolog (document type definition). Alternatively we could, for instance, pass '(pp prolog epilog) which asks for HTML pretty printing, document prolog, and document epilog.
The expression
uses quite a few of the so-called mirror functions: html, head, body, h1, table, tbody, tr, and td. These functions correspond directly to the elements (tags) of HTML. The expression is evaluated to some internal structure (not shown in full)(html (head (title "Factorials")) (body (h1 "Factorials") (table 'border "1" (tbody (tr (td "1") (td (as-string (fac 1)))) (tr (td "2") (td (as-string (fac 2)))) (tr (td "3") (td (as-string (fac 3)))) (tr (td "4") (td (as-string (fac 4)))))) ))
which can be rendered as(ast "html" ((ast "head" ((ast "title" ("Factorials") () double)) () double) ... ) () double)
Notice that we call (fac 1), (fac 2), etc. and that we convert the number to strings using as-string, which is a function from the general LAML library.<html> <head><title>Factorials</title></head> <body><h1>Factorials</h1> <table border = "1"> <tbody> <tr><td>1</td> <td>1</td></tr> <tr><td>2</td> <td>2</td></tr> <tr><td>3</td> <td>6</td></tr> <tr><td>4</td> <td>24</td></tr> </tbody> </table> </body> </html>
Finally, the expression (end-laml) says goodbye in a gentle way, and it reports about time consumption. It is not strictly necessary to call end-laml.
We process the LAML document by simply running it as a Scheme program. As mentioned, a tiny bit of contextual information is passed to the Scheme interpreter: laml-dir, the name of the source file (source-filename-without-extension), and the directory in which the file is located (startup-directory). The easiest way to process the document is from Emacs, where the laml mode binds the C-o (Control o) key to a command that activates your Scheme interpreter. Laml mode in Emacs also offers a menu with a lot of different commands. Try it out on the files in the example directory! You can also, from Emacs, activate M-x run-laml-interactively and then issue the command
(laml "fac-1")You also find run-laml-interactively in the Tools > Laml menu of Emacs. Notice that the run-laml-interactively command should be called on a buffer, which presents some file in the appropriate directory. You can also just start your Scheme system, define laml-dir and the contextual information, and then load the laml program by (load "fac-1.laml").
![]() ![]() ![]() 2.2 Another factorial page |
The innermost mapping applies the function
on the list (1 .. 50). The function number-interval is one of functions from the LAML general library. The innermost mapping produces a list like(lambda (n) (list (td (as-string n)) (td (as-string (fac n)))))
Actually, the elements are not HTML strings, but instances of internal abstract syntax trees which can be rendered as the HTML strings shown above.( ("1 " "1 ") ("2 " "2 ") ("3 " "6 ") ("4 " "24 ") ... )
The outermost mapping applies the tr function on the rows. In this situation it is crucial that the contents of an HTML mirror function can be a list of contents elements. (This aspect of the mirror functions is discussed thoroughly in another section of the LAML tutorial). The outermost mapping produces
Again - the elements of the list are actually syntax trees. This list serves as contents to tbody, which is a constituent of the table function.( "" " 1 1 " " 2 2 " " 3 6 " ... ) 4 24
![]() ![]() ![]() 3 LAML processing In this section we will discuss a few important LAML processing topics, including the concept LAML load safeness. |
3.1 LAML processing |
![]() ![]() ![]() 3.1 LAML processing |
As discussed on the LAML software home page, LAML processing can be activated in different ways.
Personally, I almost always initiate LAML processing from Emacs, using the Emacs command laml-process-current-buffer (which is bound to C-o in my Emacs setup as well as in the default LAML Emacs setup in the LAML distribution.).
Sometimes, it is attractive to initiate LAML processing by means of the function laml. We have, for instance, arranged that all LAML examples in all tutorial
example directories can be re-processed automatically. The LAML examples related to 'getting started', are processed by the script process-all.laml.
The function process-list processes a list of laml files. The actual processing is done at the location of the laml procedure ().
In general, we want to be able to write
(laml-cd "dir") (laml "file") (laml-cd "..")
in order to process 'file.laml' in 'dir'. For that to succeed it is important that all kinds of file access in 'file.laml' is relative to the LAML startup-directory. In the example above, laml-cd sets the startup-directory. When the 'outer level' of LAML processing start, we always transfer knowledge about the current directory (the startup directory).
We have decided, at an early point in time, that all file access is handled explictly. In principle we always access files via use of full path information. This stands as a contrast to using load path (ala Emacs load paths, or java class paths).
We say that a LAML program is LAML load safe, if each and every file access (inclusive file loading) is either absolute, or relative to the startup directory. The function in-startup-directory is handy in this respect. When we write something like
(read-text-file (in-startup-directory "file.txt"))
or
(load (in-startup-directory "file.scm"))
We ensure that 'file.txt' and 'file.scm' are accessed relative to the LAML startup directory.
There are more LAML processing examples in examples/processing/ in the LAML distribution.
![]() ![]() ![]() 4 Bookmarks We now approach a much more realistic problem, namely the handling of bookmarks. If you like to see LAML in play with some Scheme programs, you are invited to read through the details. If not, you may safely proceed to the chapter on mirror function, which is the next part of the tutorial. |
4.1 Bookmark administration 4.2 The frameset section 4.3 Bookmark selectors and constructor 4.4 The left frame 4.5 The right frame |
![]() ![]() ![]() 4.1 Bookmark administration |
The example is rather typical, because it is based on data that are represented in a simple data structure. The data represent some facts and relationships which we want to display on a web page.
As a motivation we can observe that it is not pratical to bind one's bookmarks to a single machine, nor to a single browser. I use several different machines, on both the Unix and the Windows platform. Therefore I maintain my bookmarks as a datastructure, from which I generate a HTML presentation of the bookmarks.
Let us assume that each bookmark is of the form
Thus, a bookmark is a four tuple of a symbol, a bookmark category string, and a comment. The collection of bookmarks, which we represent in a file, is a list of bookmark entries with no particular ordering imposed. Given such a list, we will here make a bookmark browser, such as this one (If the example does not show up the browser, then please find it in 'the background' - we reuse browser windows for various purposes).(bookmark "title" "category" "comment")
The sample bookmark data file is available as bookmark-data.
![]() ![]() ![]() 4.2 The frameset section |
We first define the variable frame-width-list
which defines the widths of the browsers 'column' frames. Next in the section
frameset-page we generate
the frameset page. This is a page with head ( The frameset page actually causes validation problems, because a html page, strictly speaking,
must have a head and a body. Try process bookmarks.laml in the example directory
examples/tutorial/getting-started/.
However, the frameset variation of the HTML4.01 DTD allows us to
substitute the body with a frameset. Therefore we just ignore the validation warning, which is issued. We see that we make empty frame pages using make-empty-page!. These empty pages
will later in the program be overwritten by more useful frame pages. ), title (
), and two frames (
).
Both the head, title, and the frame forms are applications of HTML mirror functions. Frames are named
(for mutual reference purposes)
and sourced (in order to bring up other WWW pages in the frames).
Notice the use of frame-width-list (at
): we use the function list-to-string
to create a comma separated value of the cols attribute. The resulting frameset is written
to a HTML file of the same name as the source LAML file (
). This is the default behavior of
the write-html procedure. Thus, if the source
document is located in index.laml, the frameset will be written to index.html.
![]() ![]() ![]() 4.3 Bookmark selectors and constructor |
![]() ![]() ![]() 4.4 The left frame |
The function present-categories takes a bookmark list, bml, as parameter. The value of the variable bookmarks is passed as actual parameter to this function. The bookmarks as such come from a file, such as bookmark-list, as it appears in the definition of bookmarks.
Let us now take a closer look at the function present-categories. It first extract
all bookmark categories by mapping the selector function bookmark-category-of
on the bookmark list bml ( In the body of present-categories we render anchors to the bookmark file (as they are presented in the right frame).
This is done my mapping ( ). This will typically create a list with a lot of duplicates,
because each category of bookmarks, in general, will contain many individual bookmarks.
Therefore we remove the duplicates from the category list (
).
) a specially made, simple lambda function on the sorted and
downcased category list, cat-list-unique. Notice that the downcasing is
done in the comparator function (the lambda expression) in order not to change the letter case of
the anchor names as such. (Doing so causes a result, which will not work in Netscape and Mozilla, but it
is OK in MS explorer).
The lambda function returns targeted hyper references.
We here use the function a-tag-target from the HTML convenience library to
create the a (anchor) element. Alternatively, we could of course use
the a mirror function (the Scheme mirror of the HTML element called a) directly together with appropriate attributes.
Notices that we rely on anchor names (in terms of the categories), which we assume will be found in the bookmarks.html file.
As such it will probably be a requirement that the category names of the bookmarks are without spaces or
other kinds of white space.
![]() ![]() ![]() 4.5 The right frame |
cat1 bookmark-1 bookmark-2 bookmark-3 cat2 bookmark-4 bookmark-5 bookmark-6The first task is to order the bookmarks according to their categories. This is done in the 'top level function' present-bookmarks. The ordering is done by the Scheme/LAML sort-list function (
Now present-bookmarks-1 takes over the rest of the presentation work.
The main challenge i present-bookmarks-1 is to present the bookmark category
in front of only the first bookmark in a given category. This is somewhat tricky.
Our functional solution is the following. In the last two lines of present-bookmarks
we use two list: the sorted bookmarks () and a right shifted copy of it (
).
If we assume that (b1 b2 b3 b4 b5) is the list of sorted bookmarks, the
right shifted copy is (x b1 b2 b3 b4). X is a special sentinel-bookmark.
Now given these two lists
(b1 b2 b3 b4 b5) (x b1 b2 b3 b4)as bml and prev-bml in present-bookmarks-1, we emit a category header if the category of bm is not equal to the cateory of bm-pre (
The presentation of a single bookmark is simple; It is done by present-a-bookmark.
Notice how the bookmark comment is used as the title attribute of the anchor tag ( The right frame is written in the program section right-frame-page. ).
![]() ![]() ![]() 5 Epilogue We will summarize what we have learned here, and what we need to be concerned with next. |
5.1 Epilogue |
![]() ![]() ![]() 5.1 Epilogue |
In this chapter of the tutorial we have studied some applications of LAML, in which some data are present in lists. First we showed how a function, fac, can be mapped on a list of numbers, and not least how to present the results on a web page. Next we showed a real-life task, namely how to generate a frame-based web page for a collection of bookmarks.
We have encountered various HTML mirror functions already. In the next chapter of the tutorial we will more systematically study the mirror functions of HTML. This insight can be used on XML as well. In general, you can navigate between neighbor chapters of the tuturial by using the right arrow icon in the top banner of this window.