[Home] [Tech Library] Appendix: Code for the alert algorithmThe 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. [Home] [Tech Library] |