> yes.  there are a couple (okay, three) problems to address here.  byron and 
> paul haahr
> addressed some of the problems with a shell called "es" years ago, even 
> though they
> didn't have dynamic modules.

i had es in mind when i wrote the inferno shell (vita nuova's, not the original 
tiny shell).
i thought then that some of the es concepts were nice, but the whole complete 
functional language
thing was overkill and didn't get one very far (why make it possible to redefine
core shell concepts such as the pipe? - it just confuses everyone if you make 
use of this.)

inferno made it very easy to provide "internal" modules (which i called 
"builtins";
i never really thought of a satisfactory name) - the interface they get to
see is a restricted version of the interface seen by the shell itself 
internally.
i tried to keep this as clean as possible. (by contrast, mash, which did a 
similar
thing, had quite a complex interface at this level).

> es did this: anything passed to a function inside curly braces was passed 
> verbatim.

that was the main bit of es that i stole for the inferno shell. it works well,
and combined with dynamically loaded shell modules, makes many nice things quite
easy.

for instance:
>       ; if {condition1} {body1} {condition2} {body2}

is not implemented by the core inferno shell, but by an externally loaded
module (std).

since then, shell modules have been implemented for all kinds of things (e.g. 
graphics,
s-expression parsing, mash-like make).
externally implemented programs are still preferable (smaller interface,
the shell doesn't break if the program does), for interfaces which
need to maintain state across calls or wish to call back into the shell,
a shell module can work well. it also makes it easy (and efficient)
for a function in such a module to return a list of values (the fundamental
type).

the main problem is that a shell of this style
has no concept of storage of any item but a string (ok, a list of strings), so 
it is not
possible to manipulate other data items directly. also, the interface makes
it quite natural to pass code fragments to external programs to execute,
e.g.
        listen 'tcp!*!6666' {export /&}
but the external programs don't have access to the original shell's
environment (e.g. loaded shell modules).

i don't think it's possible to address these problems without
breaking the simplicity of the whole thing; the moment you
introduce lexical binding, differently typed variables, etc,
a whole raft of other issues starts to drift into view.
another kind of language might begin to help, but that's another
story.

just having shell blocks as values is a big win, in my book.
i don't think it would be hard to do this in rc.

> a trivial grep module could make
>       ; grep {^fn} *.[ch]
> acceptable syntax.

i'm sorry, i don't see why this is preferable to the original.
it has the same number of characters.

Reply via email to