Skip to content

Commit fcdeaac

Browse files
committed
add a fold_effect function.
1 parent 7f5001c commit fcdeaac

2 files changed

Lines changed: 54 additions & 0 deletions

File tree

effect/fold.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from effect import Constant, Effect
2+
3+
4+
_sneaky = object()
5+
6+
def fold_effect(f, initial, effects):
7+
"""
8+
Fold over effects.
9+
10+
The function will be called with the accumulator (starting with
11+
``initial``) and a result of an effect repeatedly for each effect. The
12+
result of the previous call will be passed as the accumulator to the next
13+
call.
14+
15+
:param callable f: function of ``(accumulator, element) -> accumulator``
16+
:param initial: The value to be passed as the accumulator to the first
17+
invocation of ``f``.
18+
:param effects: sequence of Effects.
19+
"""
20+
21+
def folder(acc, element):
22+
# A bit of a hack here. We could just wrap `initial` in a
23+
# Effect(Constant()), but to simplify testing we avoid the additional
24+
# Effect by "sneaking" it in this way.
25+
26+
# This way people can use SequenceDispatcher and not get anything
27+
# unexpected.
28+
if acc is _sneaky:
29+
return element.on(lambda r: f(initial, r))
30+
else:
31+
return acc.on(lambda r: element.on(lambda r2: f(r, r2)))
32+
33+
return reduce(folder, effects, _sneaky)

effect/test_fold.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
import operator
3+
4+
from effect import Constant, Effect, sync_perform
5+
from effect.fold import fold_effect
6+
from effect.testing import SequenceDispatcher
7+
8+
9+
def test_fold_effect():
10+
effs = [Effect('a'), Effect('b'), Effect('c')]
11+
12+
dispatcher = SequenceDispatcher([
13+
('a', lambda i: 'Ei'),
14+
('b', lambda i: 'Bee'),
15+
('c', lambda i: 'Cee'),
16+
])
17+
eff = fold_effect(operator.add, 'Nil', effs)
18+
19+
with dispatcher.consume():
20+
result = sync_perform(dispatcher, eff)
21+
assert result == 'NilEiBeeCee'

0 commit comments

Comments
 (0)