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
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.