[Home] [Tech Library]

Appendix: Code for the alert algorithm

The alert algorithm is the most procedurally intricate of the initial strategies described here, hence it is the one least suited to description in English. It is documented here by code written in the programming language FCP [V,16]; this code has not been run. To facilitate object-oriented programming, we are using a form of syntactic sugar known as "keyword terms" [17]. A keyword term can be distinguished from the familiar positional term by use of curly braces instead of parentheses. The arguments of a keyword term are identified by the keyword to the left of the colon instead of by position. All unmentioned keywords are considered to be associated with unbound variables. The keyword term "foo{KTerm but bar:a, baz:b}" is identical to the keyword term "KTerm" except that "bar" is associated with "a" and "baz" is associated with "b". Keyword terms can be efficiently translated into positional terms.

% mem
        % Alert

        % Not idle
mem([Msg | Self], State) :-
        alert{alertID:ID, alerter:Alerter} = Msg,
        state{stateName:SName, alertID:ID} = State,
        SName =\= idle |
        Alerter = [refusal{alertID:ID}],
        mem(Self?, State).

        % IDs differ
mem([Msg | Self], State) :-
        alert{alertID:ID1} = Msg,
        state{stateName:SName, alertID:ID2} = State,
        SName =\= idle,
        ID1 =\= ID2 |
        tryToPayAlert(Msg, Self, NewSelf, State, NewState),
        mem(NewSelf?, NewState?).

        % Idle

        % alertQ empty
mem([Msg | Self], State) :-
        alert{} = Msg,
        state{stateName:idle, alertQ:[]} = State |
        tryToPayAlert(Msg, Self, NewSelf, State, NewState),
        mem(NewSelf?, NewState?).

        % alertQ non-empty
mem(Self, State) :-
        state{stateName:idle, alertQ:[AlertMsg | AlertMsgs],
clients:Clients} = State |
        alert{alertID:ID, alerter:Alerter, amount:Amount} = AlertMsg,
        alertClients(Clients, alert{AlertMsg but alerter:Self1},
NumClients, NewClients),
        NewState = {State but stateName:tryingToPayAlert,
        alertID:ID, alertQ:AlertMsgs, count:NumClients?,
        clients:NewClients?},
        merge(Self?, Self1?, NewSelf),
        mem(NewSelf?, NewState?).

        % Cancel

        % Trying to pay rent
mem([cancel{alertID:ID} | Self], State) :-
        state{stateName:tryingToPayRent, alertID:ID} = State |
        mem(Self?, State).

        % Trying to pay alert
mem([cancel{alertID:ID} | Self], State) :-
        state{stateName:tryingToPayAlert, alertID:ID, clients:Clients} = 
State |
        cancelClients(Clients, cancel{alertID:ID}, NewClients),
        NewState = state{State but stateName:idle, clients:NewClients},
        mem(Self?, NewState?).

        % Waiting to be thanked
mem([cancel{alertID:ID} | Self], State) :-
        state{stateName:waitingToBeThanked, alertID:ID} = State |
        mem(Self?, State).

        % Ids differ
mem([cancel{alertID:ID1} | Self], State) :-
        state{stateName:SName, alertID:ID2, alertQ:Q} = State,
        SName =\= idle,
        ID1 =\= ID2 |
        forgetAlert(Q?, ID1, NewQ),
        NewState = state{State but alertQ:NewQ?},
        mem(Self?, NewState?).

        % Idle
mem([cancel{} | Self], State) :-
        state{stateName:idle, alertQ:[]} = State |
        mem(Self?, State).

        % Thank you

        % Trying to pay rent
mem([Msg | Self], State) :-
        thankYou{alertID:ID} = Msg,
        state{stateName:tryingToPayRent, alertID:ID} = State |
        error(Msg),
        mem(Self?, State).

        % Trying to pay alert
mem([Msg | Self], State) :-
        thankYou{alertID:ID} = Msg,
        state{stateName:tryingToPayAlert, alertID:ID} = State |
        error(Msg),
        mem(Self?, State).

        % Waiting to be thanked
mem([Msg | Self], State) :-
        thankYou{alertID:ID} = Msg,
        state{stateName:waitingToBeThanked, alertID:ID, payer:Payer} = 
State |
        Payer = [Msg],
        NewState = state{State but stateName:idle},
        mem(Self?, NewState?).

        % Ids differ
mem([thankYou{alertID:ID1} | Self], State) :-
        state{stateName:SName, alertID:ID2} = State,
        SName =\= idle,
        ID1 =\= ID2 |
        mem(Self?, State).

        % Idle
mem([thankYou{} | Self], State) :-
        state{stateName:idle} = State |
        mem(Self?, State).

        % Reimbursement

        % Trying to pay rent
mem([Msg | Self], State) :-
        reimbursement{alertID:ID} = Msg,
        state{stateName:tryingToPayRent, alertID:ID} = State |
        error(Msg),
        mem(Self?, State).

        % Trying to pay alert
mem([Msg | Self], State) :-
        reimbursement{alertID:ID} = Msg,
        state{stateName:tryingToPayAlert, alertID:ID} = State |
        error(Msg),
        mem(Self?, State).

        % Waiting to be thanked
mem([Msg | Self], State) :-
        reimbursement{alertID:ID} = Msg,
        state{stateName:waitingToBeThanked, alertID:ID, payer:Payer} = 
State |
        Payer = [Msg],
        NewState = state{State but stateName:idle},
        mem(Self?, NewState?).

        % Ids differ
mem([Msg | Self], State) :-
        reimbursement{alertID:ID1, check:Check} = Msg,
        state{alertID:ID2} = State,
        ID1 =\= ID2 |
        deposit(Check?, State?, NewState),
        mem(Self?, NewState?).

        % Idle
mem([Msg | Self], State) :-
        reimbursement{check:Check} = Msg,
        state{stateName:idle} = State |
        deposit(Check?, State?, NewState),
        mem(Self?, NewState?).

        % Payment

        % Trying to pay rent
mem([Msg | Self], State) :-
        payment{alertID:ID, check:Check, payer:Payer} = Msg,
        state{stateName:tryingToPayRent, alertID:ID, clients:Clients} = 
State |
        payRent(Check?, State?, State1),
        creditPayer(Payer, Check?, State1?, State2),
        Payer = [thankYou{alertID:ID}],
        cancelClients(Clients, cancel{alertID:ID}, NewClients), NewState =
state{State2? but stateName:idle, clients:NewClients},
        mem(Self?, NewState?).

        % Trying to pay alert
mem([Msg | Self], State) :-
        payment{alertID:ID, check:Check, payer:Payer} = Msg,
        state{stateName:tryingToPayAlert, alertID:ID, alerter:Alerter,
clients:Clients} = State |
        creditPayer(Payer, Check?, State?, State1),
        Alerter = [payment{Msg but payer:Self1}],
        cancelClients(Clients, cancel{alertID:ID}, NewClients), NewState =
state{State1? but stateName:waitingToBeThanked, payer:Payer,
clients:NewClients},
        mem(Self?, NewState?).

        % Waiting to be thanked
mem([Msg | Self], State) :-
        payment{alertID:ID, check:Check, payer:Payer} = Msg,
        state{stateName:waitingToBeThanked, alertID:ID} = State |
        Payer = [reimbursement{alertID:ID, check:Check}],
        mem(Self?, State).

        % Ids differ
mem([Msg | Self], State) :-
        payment{alertID:ID1, check:Check, payer:Payer} = Msg,
        state{stateName:SName, alertID:ID2} = State,
        SName =\= idle,
        ID1 =\= ID2 |
        Payer = [reimbursement{alertID:ID, check:Check}],
        mem(Self?, State).

        % Idle
mem([Msg | Self], State) :-
        payment{alertID:ID, check:Check, payer:Payer} = Msg,
        state{stateName:idle} = State |
        Payer = [reimbursement{alertID:ID, check:Check}],
        mem(Self?, State).

        % Refusal

        % Trying to pay rent

        % count = 0
mem(Self, State) :-
        state{stateName:tryingToPayRent, count:0} = State |
        liquidate(Self, State).

        % count > 0
mem([refusal{alertID:ID} | Self], State) :-
        state{stateName:tryingToPayRent, alertID:ID, count:Count} = State,
        Count > 0 |
        NewCount := Count - 1,
        NewState = state{State but count:NewCount?},
        mem(Self?, NewState?).

        % Trying to pay alert

        % count = 0
mem(Self, State) :-
        state{stateName:tryingToPayAlert, alertID:ID, count:0,
alerter:Alerter} = State |
        Alerter = [refusal{alertID:ID}],
        NewState = state{State but stateName:idle},
        liquidate(Self, NewState?).

        % count > 0
mem([refusal{alertID:ID} | Self], State) :-
        state{stateName:tryingToPayAlert, alertID:ID, count:Count} = State,
        Count > 0 |
        NewCount := Count - 1,
        NewState = state{State but count:NewCount?},
        mem(Self?, NewState?).

        % Waiting to be thanked
mem([refusal{alertID:ID} | Self], State) :-
        state{stateName:waitingToBeThanked, alertID:ID} = State |
        mem(Self?, State).

        % Ids differ
mem([refusal{alertID:ID1} | Self], State) :-
        state{stateName:SName, alertID:ID2} = State,
        SName =\= idle,
        ID1 =\= ID2 |
        mem(Self?, State).

        % Idle
mem([refusal{} | Self], State) :-
        state{stateName:idle} = State |
        mem(Self?, State).

% Other predicates

% tryToPayAlert
tryToPayAlert(AlertMsg, Self, NewSelf, State, NewState) :-
        alert{amount:Amount} = AlertMsg,
        collectRetainer(Amount?, State?, State1, Check, Ok),
        tryToPayAlert1(Ok?, Check?, AlertMsg, Self, NewSelf, AlertsForQ),
        state{alertQ:Q} = State1?,
        append(AlertsForQ?, Q?, NewQ),
        NewState = state{State1? but alertQ:NewQ?}.

tryToPayAlert1(true, Check, AlertMsg, Self, NewSelf, []) :-
        alert{alertID:ID, alerter:Alerter} = AlertMsg,
        Alerter = [payment{alertID:ID, check:Check, payer:Self1}],
        merge(Self?, Self1?, NewSelf).

tryToPayAlert1(false, Check, AlertMsg, Self, NewSelf, [Alert]).

% alertClients
alertClients([], AlertMsg, 0, []) :-
        alert{alerter:[]} = AlertMsg.

alertClients([Client | Clients], AlertMsg, NumClients, [NewClient |
NewClients]) :-
        alert{alerter:Alerter} = AlertMsg,
        Client = [alert{AlertMsg but alerter:Alerter1} | NewClient?],
        alertClients(Clients, alert{AlertMsg but alerter:Alerter2},
NCMinus1, NewClients),
        NumClients := 1 + NCMinus1,
        merge(Alerter1?, Alerter2?, Alerter).

% cancelClients
cancelClients([], CancelMsg, []).

cancelClients([Client | Clients], CancelMsg, [NewClient | NewClients]) :-
        Client = [CancelMsg | NewClient?],
        cancelClients(Clients, CancelMsg, NewClients).

% forgetAlert
forgetAlert([], ID, []).

forgetAlert([AlertMsg | Q], ID, Q) :-
        alert{alertID:ID, alerter:[]} = AlertMsg | true.

forgetAlert([AlertMsg | Q], ID1, [AlertMsg | NewQ?]) :-
        alert{alertID:ID2} = AlertMsg,
        ID1 =\= ID2 |
        forgetAlert(Q, ID1, NewQ).

Acknowledgments Note: see the paper "Markets and Computation: Agoric Open Systems" in this book [II] for general discussion, acknowledgments, and comparison with other work.

Previous

[Home] [Tech Library]