[Date Prev] [Date Next] [Thread Prev] [Thread Next] Date Index Thread Index Search archive:
Date:Mon Nov 17 11:44:52 2001 
Subject:Re: Syntactic errors when compiling from a ved buffer (generalised) 
From:Aaron Sloman See text for reply address 
Volume-ID:1011117.01 

[To reply replace "Aaron.Sloman.XX" with "A.Sloman"]

I previously wrote:

> I have now produced a new library file LIB newvederror, which is
> available here
>     http://www.cs.bham.ac.uk/research/poplog/lib/newvederror.p

It turned out that I forgot that the command to compile the whole of
the current file (ENTER l1) uses the procedure ved_l1, which is not
defined in terms of ved_lmr, unlike most other commands to
compile from the Ved buffer.

Consequently the new behaviour for syntactic errors did not work if
you used ENTER l1 to compile a file.

The fix was fairly simple and has now been installed at the above
site and included in the various downloadable packages. Since it
depended on the fact that ved_l1 is a closure, I give a
mini-tutorial on closures below.

Here is the revised version of vederror, which can be installed in
one of the library directories or in your personal vedinit.p file.

===================================================================
;;; Save old version of vederror
global constant oldvederror = vederror;

define vars vederror(string);

	;;; ved_l1 is a closure of an inaccessible system procedure.
	;;; we can get at the procedure like this
	lconstant l1_compiler = pdpart(ved_l1);

	if iscaller(ved_lmr) or iscaller(l1_compiler) then
		;;; compiling from marked range, so put mishap message in output file.

		if vedlmr_print_in_file then
			;;; redirect output to that file
			vedlmr_print_in_file -> ved_chario_file
		endif;
			
		printf('\n;;; MISHAP %p\n', [^string]);
		vedscreenbell();
		vedscr_flush_output();
	else
		oldvederror(string)
	endif;
enddefine;

===================================================================

MINI-TUTORIAL ON CLOSURES:

A closure is a combination of a procedure with some data "frozen" in
it, for it to operate on whenever it is run.

E.g. this

    member(%[red orange yellow green blue violet indigo]%)

combines the procedure member(item, list) with a list of words to
produce a closure that behaves like a one-argument procedure that
recognizes colour names. If applied to an argument, e.g. x
it is equivalent to
    member(x, [red orange yellow green blue violet indigo])

When the closure is run it puts the frozen values (frozvals) on the
stack and then invokes the procedure (the pdpart of the closure).

For anyone who wants to know why I could not simply use

    iscaller(ved_l1)

by analogy with

    iscaller(ved_lmr)

the reason is that ved_l1 is a closure of an inaccessible system
procedure Compile_files, defined in

    $usepop/pop/ved/src/vdcompile.p

thus
    define vars ved_l1 = Compile_files(%false, true%) enddefine;

This means that when ved_l1 is run, only the "pdpart" of the
closure, i.e. Compile_files, is on the procedure call-stack, not the
closure itself.

So iscaller(ved_l1) will ALWAYS be false.

However, extracting the pdpart of ved_l1, enables that procedure to
be used as the argument to iscaller.

The extraction is done in this line:

	lconstant l1_compiler = pdpart(ved_l1);

which is done once, at compile time, because of the lconstant
declaration, If I had used lvars, it would be done every time the
procedure runs.

So iscaller(l1_compiler) is equivalent to but more efficient than

    iscaller(pdpart(ved_l1))

Actually, in this context, the efficiency gain is *miniscule* compared
with the overhead of writing to a Ved buffer, updating the screen, etc.
etc. I merely used the more efficient version from habit!

A corollary of the above is that the new behaviour in vederror will
work in all procedures that invoke Compile_files.

For more information on partial application and different sorts of
closures in Pop-11 see

    HELP CLOSURES
    HELP PERCENT

Both available within poplog and also here

    http://www.cs.bham.ac.uk/research/poplog/doc/pophelp/closures
    http://www.cs.bham.ac.uk/research/poplog/doc/pophelp/percent

There is also information in TEACH PRIMER, e.g. in the section
headed
    -- Using "partial application" to create a closure

also available in chapter 4 of the html version

    http://www.cs.bham.ac.uk/research/poplog/primer/

For more gory detail see REF procedure, or

    http://www.cs.bham.ac.uk/research/poplog/doc/popref/procedure

Even more gory detail on lexical closures can be found in REF vmcode

NOTE
Old pop-11 experts who have not studied the HELP NEWS file may be
interested to know that in the more recent versions of poplog
(since V15.5) there is a procedure

    sys_grbg_closure

which allows the space allocated to closures to be re-used without
having to rely on the garbage collector.

This means that the cost of using closures can be significantly reduced
in some contexts, which is great since they are such a useful and
powerful programming construct in connection with procedures that take a
procedure as one of their arguments.

For example

    define apptree(tree, proc);
        ;;; recursively apply proc to every atom (non-list) in tree

        if islist(tree) then

            ;;; create closure of this procedure with proc
            lvars recurse = apptree(%proc%);

            ;;; use it with applist to scan the list
            applist(tree, recurse);

            ;;; reclaim the space used by the closure
            sys_grbg_closure(recurse);

        else
            ;;; tree is not a list, so it is an atom, and proc can be
            ;;; applied to it
            proc(tree)
        endif
    enddefine;

    ;;; EXAMPLE
    ;;; Here is a tree (a list-structure of varying depth).
    vars tree
        = [big [red [hard soft green]] [[violet]] [orange square [blue circle]]];


    ;;; We want to find every item that satisfies a membership condition.
    ;;; A closure of this procedure can be used to test individual items.
    define getmember(item, list);
        ;;; return item if it is in list, otherwise do nothing
        if member(item, list) then item endif
    enddefine;

    ;;; To find all colour words in the tree:
    ;;; Use apptree to search the tree with a closure of getmember,
    ;;; and use [% ... %] to make a list of all the results

    [% apptree(tree, getmember(%[red orange yellow green blue indigo violet]%) ) %] =>

    ;;; That produces this:
    ** [red green violet orange blue]

Aaron
====
Aaron Sloman, ( http://www.cs.bham.ac.uk/~axs/ )
School of Computer Science, The University of Birmingham, B15 2TT, UK
EMAIL A.Sloman AT cs.bham.ac.uk   (ReadATas@please !)
PAPERS: http://www.cs.bham.ac.uk/research/cogaff/ (And free book on Philosophy of AI)
FREE TOOLS: http://www.cs.bham.ac.uk/research/poplog/freepoplog.html