Created
March 6, 2015 23:16
-
-
Save allyourcode/88a25fdacba2c5a46dfd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(running_total). | |
-export([new/2, update/2, update_silently/2]). | |
-export([sum/0, truncated_sum/1]). | |
new(Reducer, Initial) -> | |
spawn_link(fun() -> run(Reducer, Initial) end) | |
. | |
update(This, Value) -> | |
Self = self(), | |
Reply = fun(Result) -> Self ! Result end, | |
This ! {Reply, Value}, | |
receive | |
Updated -> Updated | |
end | |
. | |
update_silently(This, Value) -> | |
This ! {fun(_Whatever) -> ok end, Value} | |
. | |
sum() -> | |
new(fun(X, OldState) -> | |
S = X + OldState, | |
{S} | |
end, | |
0) | |
. | |
% This clause is degenerate, but we support it anyway. Maybe negative is too | |
% degenerate and should cause an error... | |
% | |
% Example: | |
% | |
% > T = running_total:truncated_sum(3). | |
% <0.45.0> | |
% > running_total:update(T, 3). | |
% 3 | |
% > running_total:update(T, 10). | |
% 13 | |
% > running_total:update(T, 100). | |
% 113 | |
% > running_total:update(T, 1000). | |
% 1110 | |
truncated_sum(_MaxSize) when _MaxSize =< 0 -> | |
new(fun(_, _) -> {0} end, | |
ok) | |
; | |
truncated_sum(MaxSize) when MaxSize > 0 -> | |
new(fun(In, {PreviousSum, Size, OldHistory}) -> | |
if | |
Size < MaxSize -> | |
NewSum = PreviousSum + In, | |
{NewSum, Size + 1, queue:in(In, OldHistory)}; | |
Size == MaxSize -> | |
{{value, Oldest}, Popped} = queue:out(OldHistory), | |
{PreviousSum + In - Oldest, Size, queue:in(In, Popped)} | |
end | |
end, | |
{0, 0, queue:new()}) | |
. | |
run(Reducer, OldState) -> | |
receive | |
{Reply, In} -> | |
NewState = Reducer(In, OldState), | |
Reply(element(1, NewState)), | |
run(Reducer, NewState) | |
end | |
. | |
% The idea here is for this to be used as case value, which we believe is more | |
% readable when each case needs to be handled differently. Example: | |
% | |
% case cmp(Foo, Bar) of | |
% greater -> blah(); | |
% equal -> bleh(); | |
% less -> blag() | |
% end | |
% | |
% I think this is better than if using this, the operands are the same in each | |
% case. Also, this guides programmer to think about how the three cases need to | |
% be handled differently. | |
% | |
% Also, by omitting explicit handler, one can implicitly assert that such case | |
% should not happen, and should result in crash. | |
cmp(V1, V2) -> | |
if | |
V1 > V2 -> greater; | |
V1 == V2 -> equal; | |
V1 < V2 -> less | |
% else, wtf?? | |
end | |
. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment