[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gnu-arch-users] Round IV: xl and all that (looking ahead, mostly)
From: |
Tom Lord |
Subject: |
[Gnu-arch-users] Round IV: xl and all that (looking ahead, mostly) |
Date: |
Fri, 23 Jul 2004 18:55:59 -0700 (PDT) |
xl1: Side Effects, Multiprogramming, and Make
So far, all of the functions we've looked at in xl1 are like
(+ 1 2)
or
(concat "hello" " " "world")
Those are boring because they return a value but have no other
effect on the world.
Suppose instead that we had a function:
(print <string>)
which, in stream-oriented environments, prints <string> on "standard
output". The `print' function should return #false if the write
fails; #true if it succees.
Another interesting function to add might be:
(exit <status>)
which, if evaluated, causes the process to exit with the indicated
numeric status (#false counting as 2, all non-numbers counting as 0,
and all numbers counting as their truncated integer equivalent).
Now consider evaluating this xl1 program for the value of `main':
(define main
(exit (and (print "hello")
(print " ")
(print "world\(nl)"))))
There is at least a plausible suggestion here that xl1 with side
effects might be a handy way to write some kinds of program.
* xl1: Side Effects
Consider a typical `tla' command. They are almost all of the
general form:
main ()
{
parse the options and arguments and set some variables
based on what they say
analyze the variables set during option and argument
parsing, filling in any that are needed but not
yet set with the implied default or derived value
pass the variables to a function call into the core of
libarch, exiting with status 0 if the
}
There are no loops or recursion in that and it comes out
interestingly if you rephrase it in xl1:
; the interactive commit command....
;
(define main
(exit
(cond
((equal? function 'help) show-help-message)
((equal? function 'version) show-version-message)
(#true
; usual case:
;
(commit tree-root commit-version log-message)))))
(define parsed-options (getopt option-rules argv))
(define function
(cond
((ref parsed-options '--help) 'help)
((ref parsed-options '--version) 'version)
(#true 'commit)))
(define target-archive
(or (archive-of target-specifier)
default-archive))
(define default-archive
(or (ref parsed-options '-A-argument)
my-default-archive))
[...]
As the definition expands (barely) from xl1 to xl I'll a few
more constructs that make imperative programming practical and
interesting but, already in xl1, you can see how that might be.
And, again: a very simple interpreter can run that program, sure,
but it's also easy to translate into C.
* xl1: Multi-Programming
So far our rules for order of execution are pretty boring, for
example, the subexpressions of a function call are evaluated left to
right.
Suppose we add a new special form (which turns out to be easy to
implement) `first':
(first <subexp-0> <subexp-1> ....)
asked to reduce a `first' expression, a cycle can make progress
by reducing a trivial subexpression in _any_ of `<subexp-N>'
subexpressions, not just the left-most. It's unspecified what
order the subexpressions will be reduced.
If we assume that `first' is "fair" in how it allocates cycles among
subexpressions, then you could ask which your xl1 implementation
can evaluate faster:
(define race (first (fibonacci 50)
(factorial 14)))
or which net connection is faster:
(define document
(first (wget "http://www.gnu.org/...")
(wget "http://www.gnu-mirror.org/...")))
A daemon could be implemented as a program that listens for
requests from multiple sources:
(define this-request
(first request-from-email
request-listening-on-http
request-listening-on-udp-port))
Another special form, similar to `first', can evaluate
all subexpressions in parallel into all are finished:
(define prerequisits-done
(parallel-and prereq-a
prereq-b
prereq-c))
distributes cycles to reducing each of the three `prereq-*'
expressions until all are completely reduced or any one of them
reduces to #false.
* Make
The traditional unix build program, `make(1)', is an aweful
lot like xl1. In fact, with a suitable addition of primitives,
xl1 would make a pretty interesting `make(1)' replacement:
(define all
(and (parallel-and <all-prereq-0>
<all-prereq-1>
<all-prereq-2>
...)
<recipe to run for "all">))
One thing that makes this alternative to `make' very attractive
is that expression evaluation (such as for setting make variables)
and dependency building are both instances of the same general
thing: xl1 expression evaluation.
* Next Step
For the next step I'll build an xl1 interpreter by writing
a meta-circular xl1 vm (xl1 vm written in xl1) and either
hand-translating it to C or writing a specialized xl1->C compiler
for that.
-t
----
Like my work on GNU arch, Pika Scheme, and other technical contributions
to the public sphere? Show your support!
https://www.paypal.com/xclick/business=lord%40emf.net&item_name=support+for+arch+and+other+free+software+efforts+by+tom+lord&no_note=1&tax=0¤cy_code=USD
and
address@hidden for www.moneybookers.com payments.
-----
"Hello, all of you boys and girls,
I'd like to take you to the inside world."
- Claypool
- [Gnu-arch-users] Round IV: xl and all that (looking ahead, mostly),
Tom Lord <=