EBasic

ttinc :: Comp

The operations get and put to retrieve and update the current state were already defined, in Sec. 1. We repeat the definitions below, along with the sample term ttS , for ease of reference.

class GlobalIntState d where get :: d put :: d -> d ttS :: (EBasic d, ECond d, GlobalIntState d) => d ttS = if_ (eq `app` (int 3) `app` (put ttinc)) (put (int 10)) (put (inc `app` get))

To give the meaning to get , put and eventually ttS , Sec. 1 had to introduce the special denotation domain DomIntState , and the corresponding instances of EBasic and other type classes. In the new approach, the earlier defined Comp suffices. We only need to reveal more of ReqT : requests to access and update the state.

data ReqT = ReqError | ReqState StateReq ... data StateReq = Get | Put Int instance GlobalIntState Comp where get = Req (ReqState Get) Done put e = bind e $ \x -> case x of DCInt x -> Req (ReqState (Put x)) Done _ -> err

The meaning of get and put hence is essentially the ReqState request: for example, get sends the request and immediately returns the reply. Since Comp is unchanged, and the instances EBasic Comp and ECond Comp have been written earlier, we can see the meaning of ttS right away:

*EDSLNG> ttS :: Comp ReqState (Put 4)

ttS

ReqError

ReqState

handleState :: Int -> Comp -> Comp handleState _ (Done x) = Done x handleState s (Req (ReqState r) k) = case r of Get -> handleState s $ k (DCInt s) Put s -> handleState s $ k (DCInt s) -- everything else handleState s (Req r k) = Req r (handleState s . k)

The handler handleState is the authority that Cartwright and Felleisen were talking about, in charge of resources -- state in our case -- and replying to requests. When the computation to handle is the Get request, the handler replies with the current state, and continues handling the replied-to computation in case it has other requests. The last line in handleState deals with requests other than ReqState ; they are propagated up, or, `sent to a higher authority'. This line is the difference of our approach from Cartwright and Felleisen: to us, there is no central authority stationed outside the program. Our handlers are localized: part of the program, forming a bureaucracy. What one cannot handle gets sent to a superior.

The sample expression ttS with the state handler in the initial state 0, that is, handleState 0 ttS has the meaning of DInt 5 . We have already pointed out that the handler is recursive: after receiving a reply, an expression may send further requests, to be handled in turn. Strictly speaking therefore, the mathematical mapping established by handlers is a fixpoint -- and we have to implicitly introduce Done bottom for a non-terminating handling computation. We saw no bottoms before since we had no divergent computations. Incidentally, an expression that sends an unending stream of Get requests is not divergent: its meaning is the productive stream of requests.

Thus the Cartwright and Felleisen's idea really works! We have added a real effect without having to re-write any of the earlier domains and interpreters. One may just as painlessly introduce other sorts of mutable state, or other effects in general. Integer literals always mean integers, and can be used as such within arbitrary effectful expressions. Cartwright and Felleisen's idea works even better than the authors have described: we made the handlers themselves be modular, each responsible for its own requests.