5  The Tao of Scheme and Unix

Most attempts at embedding shells in functional programming languages [fshEllis] try to hide the difference between running a program and calling a procedure. That is, if the user tries

(lpr "notes.txt")
the shell will first treat lpr as a procedure to be called. If lpr isn't found in the variable environment, the shell will then do a path search of the file system for a program. This sort of transparency is in analogy to the function-binding mechanisms of traditional shells, such as ksh.

This is a fundamental error that has hindered these previous designs. Scsh, in contrast, is explicit about the distinction between procedures and programs. In scsh, the programmer must know which are which -- the mechanisms for invocation are different for the two cases (procedure call versus the (run . epf) special form), and the namespaces are different (the program's lexical environment versus $PATH search in the file system).

Linguistically separating these two mechanisms was an important design decision in the language. It was done because the two computational models are fundamentally different; any attempt to gloss over the distinctions would have made the semantics ugly and inconsistent.


Unix:
Computational agents are processes,
communicate via byte streams.
Scheme:
Computational agents are procedures,
communicate via procedure call/return.
Figure 4:  The Tao of Scheme and Unix


There are two computational worlds here (figure 4), where the basic computational agents are procedures or processes. These agents are composed differently. In the world of applicative-order procedures, agents execute serially, and are composed with function composition: (g (f x)). In the world of processes, agents execute concurrently and are composed with pipes, in a data-flow network: f | g. A language with both of these computational structures, such as scsh, must provide a way to interface them. {Note Normal order} In scsh, we have ``adapters'' for crossing between these paradigms:

Scheme Unix
Scheme        (g (f x))        (<< ,x)
Unix        run/string,...f | g
The run/string form and its cousins (section 3.5) map process output to procedure input; the << i/o redirection maps procedure output to process input. For example:

(run/string (nroff -ms)
            (<< ,(texinfo->nroff doc-string)))
By separating the two worlds, and then providing ways for them to cross-connect, scsh can cleanly accommodate the two paradigms within one notational framework.