Skip to content

Instantly share code, notes, and snippets.

@allyourcode
Created March 6, 2015 23:16
Show Gist options
  • Save allyourcode/88a25fdacba2c5a46dfd to your computer and use it in GitHub Desktop.
Save allyourcode/88a25fdacba2c5a46dfd to your computer and use it in GitHub Desktop.
-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