The POSIX environment

Timber is intended to be usable in many different situations, ranging from embedded systems to standard desktop applications. The interfaces between the Timber program and the external environment are very different in these cases.

Thus a Timber application must be built for a particular target environment. This distribution provides only one environment, the POSIX environment. Also this is incomplete and a more complete version will be provided in a future release.

module POSIX where
    
type RootType = Env -> Class Prog

type Prog = Action

struct Env where
    exit      :: Int -> Request ()
    argv      :: Array String
    stdin     :: RFile
    stdout    :: WFile
    openR     :: String -> Request (Maybe RFile)
    openW     :: String -> Request (Maybe WFile)
    startTime :: Time
    inet      :: Internet

struct Closable where
    close :: Request ()

struct File < Closable where
    seek  :: Int -> Request Int
    
struct RFile < File where
    read     :: Request String
    installR :: (String -> Action) -> Request ()
    
struct WFile < File where
    write    :: String -> Request Int
    installW :: Action -> Request ()

data Host = Host String
data Port = Port Int

struct Internet where
    tcp :: Sockets

struct Socket < Closable where
    remoteHost :: Host
    remotePort :: Port
    inFile     :: RFile
    outFile    :: WFile

struct Connection < Closable where 
    established :: Action
    neterror    :: String -> Action

struct Sockets where
   connect :: Host -> Port ->
              (Socket -> Class Connection) -> Request()
   listen  :: Port ->
              (Socket -> Class Connection) -> Request Closable

instance showHost :: Show Host
showHost = struct
   show (Host nm) = nm

The root module of a program targeted for this environment must import POSIX and contain a definition root :: RootType.

Here the type Env collects the services that the environment provides to the program: the program can call a function exit to terminate the program with a status indication, access command line arguments through argv, the standard input and output streams as stdin and stdout, open files for reading and writing, etc. Within a definition

root env = ...
these services are accessed using dot notation as env.argv etc.

The read and write on files are non-blocking operations:

Because of the non-blocking nature of input and output, programs need a way to be notified when input is available or output is possible. This is the role of listeners or callbacks; a call

env.stdin.installR inpHandler

installs the action inpHandler as a listener on stdin; whenever input is available (i.e. the user strikes return), the runtime system calls the listener with the input line as argument.

The startTime denotes a Time value, representing the time elapsed since the Epoch. One main use of this value is that its least significant part can serve as random generator seed.

The selector inet provides support for network programming, described on a separate page.

Execution of a program proceeds as follows. The runtime system is responsible for initialization: it creates an environment object with interface env :: Env, applies root to env and creates an object of the resulting class; this gives an interface to the initial action of the program. The run-time system executes this action; this may lead to creation of more objects, scheduling of future actions etc.

After this initial computation the program comes to rest and reacts to events, such as scheduled timer events or IO events on files with installed listeners.