Skip to content

Commit 8d86762

Browse files
committed
Merge pull request #52 from python-effect/sequence
add a `sequence` function based on `fold_effect`
2 parents d0b949f + ff2185e commit 8d86762

2 files changed

Lines changed: 59 additions & 1 deletion

File tree

effect/fold.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,20 @@ def folder(acc, element):
5757
error=lambda e: failed(r, e)))
5858

5959
return reduce(folder, effects, Effect(Constant(initial)))
60+
61+
62+
def sequence(effects):
63+
"""
64+
Perform each Effect serially, collecting their results into a list.
65+
66+
:raises: :obj:`FoldError` with the list accumulated so far when an effect
67+
fails.
68+
"""
69+
# Could be: folder = lambda acc, el: acc + [el]
70+
# But, for peformance:
71+
l = []
72+
73+
def folder(acc, el):
74+
l.append(el)
75+
return l
76+
return fold_effect(folder, l, effects)

effect/test_fold.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from effect import (
77
ComposedDispatcher, Effect, Error,
88
base_dispatcher, sync_perform)
9-
from effect.fold import FoldError, fold_effect
9+
from effect.fold import FoldError, fold_effect, sequence
1010
from effect.testing import SequenceDispatcher
1111

1212

@@ -62,3 +62,44 @@ def test_fold_effect_errors():
6262
assert excinfo.value.accumulator == 'NilEi'
6363
assert excinfo.value.wrapped_exception[0] is ZeroDivisionError
6464
assert str(excinfo.value.wrapped_exception[1]) == 'foo'
65+
66+
67+
def test_sequence():
68+
"""Collects each Effectful result into a list."""
69+
effs = [Effect('a'), Effect('b'), Effect('c')]
70+
dispatcher = SequenceDispatcher([
71+
('a', lambda i: 'Ei'),
72+
('b', lambda i: 'Bee'),
73+
('c', lambda i: 'Cee'),
74+
])
75+
eff = sequence(effs)
76+
77+
with dispatcher.consume():
78+
result = sync_perform(_base_and(dispatcher), eff)
79+
assert result == ['Ei', 'Bee', 'Cee']
80+
81+
82+
def test_sequence_empty():
83+
"""Returns an empty list when there are no Effects."""
84+
assert sync_perform(base_dispatcher, sequence([])) == []
85+
86+
87+
def test_sequence_error():
88+
"""
89+
Allows :obj:`FoldError` to be raised when an Effect fails. The list
90+
accumulated so far is the `accumulator` value in the :obj:`FoldError`.
91+
"""
92+
effs = [Effect('a'), Effect(Error(ZeroDivisionError('foo'))), Effect('c')]
93+
94+
dispatcher = SequenceDispatcher([
95+
('a', lambda i: 'Ei'),
96+
])
97+
98+
eff = sequence(effs)
99+
100+
with dispatcher.consume():
101+
with raises(FoldError) as excinfo:
102+
sync_perform(_base_and(dispatcher), eff)
103+
assert excinfo.value.accumulator == ['Ei']
104+
assert excinfo.value.wrapped_exception[0] is ZeroDivisionError
105+
assert str(excinfo.value.wrapped_exception[1]) == 'foo'

0 commit comments

Comments
 (0)