What is unimplemented?
Unimplemented exercises (which are not deprecated): {'8066003b-f2ff-437e-9103-66e6df474844', 'd7fcad99-e88e-40e1-a539-4c519681f390'}
Both of those missing exercises currently fail when run with the example.py
.
Detecting unimplemented
>>> t = pathlib.Path("tests.toml").read_text()
>>> u = toml.loads(t)
>>> old = {v.get('reimplements') for v in u.values() if 'reimplements' in v}
>>> missing = {k for k, v in u.items() if not v.get('include', True) and k not in old}
>>> missing
{'8066003b-f2ff-437e-9103-66e6df474844', 'd7fcad99-e88e-40e1-a539-4c519681f390'}
Generate tests and run tests
» ./bin/generate_tests.py list-ops && ./bin/test_exercises.py list-ops
...
FAILED list_ops_test.py::ListOpsTest::test_foldl_direction_dependent_function_applied_to_non_empty_list - ZeroDivisionError: integer division or modulo by zero
FAILED list_ops_test.py::ListOpsTest::test_foldr_direction_dependent_function_applied_to_non_empty_list - AssertionError: 1 != 9
Understanding the first failure
What went wrong with d7fcad99-e88e-40e1-a539-4c519681f390
? The reimplementation explicitly says it requires /
to support floats and to use the original/reimplemented test if using //
.
Options?
- Use the original “deprecated” test.
- Use
/
and not //
.
Suggestion: Since //
is used for this test and only this test, the Jinja template can simply drop function.replace("/", "//")
from the preprocesor and stick with /
. This lets us make fewer changes to the original data and pass more tests with the existing solution.
Details of the first test (comment from the problem spec)
canonical-data.json
{
"description": "direction dependent function applied to non-empty list",
"comments": "[...] Expects / to preserve fractions. Integer division will not work here, since it would compute 1 / 24 = 0. Use the original test values (d2cf5644-aee1-4dfc-9b88-06896676fe27) if integer division is expected / required."
}
Suggested Diff
{% set function = function.replace("modulo", "%") %}
- {% set function = function.replace("/", "//") %}
lambda {{function}}
Understanding the second failure
What went wrong with 8066003b-f2ff-437e-9103-66e6df474844
? The example.py
expects the function to take args (element, accumulator)
but the test passes a function which takes args (accumulator, element)
. If we assume the canonical data is correct ("function": "(acc, el) -> el / acc"
), then the example.py
has a bug where it swaps the arguments.
We could change the example.py so it implements what the problem spec lays out: a function which takes (acc, el)
and not (el, acc)
.
Issue: there is a Python-specific additional test which relies on the function taking (el, acc)
. This means the Python-specific test and the canonical data require different behaviors. One (canonical) requires calling acc = func(acc, el)
and the other (Python) requires acc = func(el, acc)
. Bringing this exercise in line with the canonical data will break all current solutions. It’s simple to update the Python specific test to bring it in line with the canonical data.
Suggestion: Bring the Python tests in line with the canonical data, even though it does break existing solutions.
Details of implementation error
The Jinja generated foldr
test uses a signature lambda acc, el
. The example.py
solution has a call function(list[0], foldr(function, list[1:], initial))
. Note the lambda
expects acc, el
while the implementation passes el, acc
.
Python test which has requirements different from the canonical data
def test_foldr_foldr_add_string(self):
self.assertEqual(
foldr(lambda x, y: x + y, ["e", "x", "e", "r", "c", "i", "s", "m"], "!"),
"exercism!",
)
Suggested Diff
In line with the unit test, which reads, lambda acc, el
:
# example.py
- return function(list[0], foldr(function, list[1:], initial))
+ return function(foldr(function, list[1:], initial), list[0])
# additional_tests.json
"input": {
"list": ["e", "x", "e", "r", "c", "i", "s", "m"],
"initial": "!",
- "function": "(x, y) -> x + y"
+ "function": "(acc, el) -> el + acc"
},
Conclusion
One foldl
test can be easily added by removing a transformer line from the test generator. This has no impact on existing solutions and allows adding one additional canonical test for foldl
.
Suggested Diff
# template.j2
{% set function = function.replace("modulo", "%") %}
- {% set function = function.replace("/", "//") %}
lambda {{function}}
The other missing test is for foldr
. This one is sticky. The problem spec says functions take func(acc, el)
and enforces this via the missing test. The example.py
and the additional Python-specific test enforce func(el, acc)
. We could bring Python in line with the canonical data and add the missing test, but this will break existing solutions and require a slight modification to the Python specific test.
My personal opinion is that we should bring Python in line with the canonical specs.
Suggested Diff
In line with the unit test, which reads, lambda acc, el
:
# example.py
- return function(list[0], foldr(function, list[1:], initial))
+ return function(foldr(function, list[1:], initial), list[0])
# additional_tests.json
"input": {
"list": ["e", "x", "e", "r", "c", "i", "s", "m"],
"initial": "!",
- "function": "(x, y) -> x + y"
+ "function": "(acc, el) -> el + acc"
},
I put those changes into a commit. If those changes sound good to you, @BethanyG, I can request a PR for those changes.