Skip to content

Commit bef423e

Browse files
Address Class A Accretive failures (#275)
1 parent 686a86a commit bef423e

17 files changed

Lines changed: 168 additions & 127 deletions

File tree

accretive-audit.md

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -47,42 +47,44 @@ Run it with `FACTOR=/path/to/factor bin/check-accretive [slug...]`.
4747

4848
## Results
4949

50-
The initial audit found 11 of 47 not Accretive. The 5 Mode-B exercises have
51-
since been fixed (test-only changes); 6 remain open (5 Mode A + 1 structural).
50+
The initial audit found 11 of 47 not Accretive. The 5 Mode-B and 5 Mode-A
51+
exercises have since been fixed; only the 1 structural case remains open.
5252

5353
| Verdict | Count | Exercises |
5454
|---|---|---|
55-
| Accretive | 41 | all others |
56-
| Mode A (open) | 5 | bering-bearings, boatswains-bilge, dragons-descendants, factory-failsafe, pirates-path |
55+
| Accretive | 46 | all others |
56+
| Mode A (fixed) | 5 | bering-bearings, boatswains-bilge, dragons-descendants, factory-failsafe, pirates-path |
5757
| Mode B (fixed) | 5 | garden-gathering, lighthouse-logbook, poetry-club, quayside-crew, tellers-triage |
5858
| Structural (open) | 1 | telegraphers-tape |
5959

60-
## Mode A — a definition is introduced after task 1
61-
62-
- **factory-failsafe**`ERROR: machine-error` is created in task 3, but the
63-
tests reference `machine-error` / `machine-error?` (tasks 3–4). The stub only
64-
has a comment, so tasks 1–2 cannot compile.
65-
*Fix:* pre-ship the error class in the stub, exactly as `rpn-calculator`
66-
already ships `zero-divisor-error`.
67-
- **pirates-path**`gold-count` (a `MEMO:` word, task 4) is left as a comment
68-
in the stub instead of a stub body, so the tests reference an undefined
69-
`gold-count` and nothing compiles.
70-
*Fix:* pre-stub it, e.g. `MEMO: gold-count ( cove -- n ) "unimplemented" throw ;`.
60+
## Mode A — a definition was introduced after task 1 (fixed)
61+
62+
- **factory-failsafe**`ERROR: machine-error` was created in task 3, but the
63+
tests reference `machine-error` / `machine-error?` at compile time, so tasks
64+
1–2 could not compile. *Fixed* by reordering so defining the error class is
65+
task 1; the check/monitor tasks follow.
66+
- **pirates-path**`gold-count` (a `MEMO:` word, task 4) was a comment in the
67+
stub, so the tests referenced an undefined `gold-count`. *Fixed* by shipping it
68+
as a `:` stub; task 4 now asks the student to change `:` to `MEMO:`.
7169
- **dragons-descendants** — the subtuples `fire-dragon` / `ice-dragon` /
72-
`volcano-dragon` and their constructors are defined across tasks 2–4 (the stub
73-
is comment-only), so implementing only task 1 leaves them undefined.
74-
*Fix:* bundle all tuple/constructor definitions into task 1.
75-
- **bering-bearings** — tuples `polar` (task 2) and `relative` (task 3), plus the
76-
direction symbols and the `>cartesian`/`flip` generics, are scattered across
77-
tasks (comment-only stub).
78-
*Fix:* bundle all tuple/symbol/generic definitions into task 1.
70+
`volcano-dragon` and their constructors were defined across tasks 2–4 (the stub
71+
was comment-only). *Fixed* by bundling the whole tuple hierarchy into task 1
72+
(the student still defines it); the descendant constructors are pre-stubbed so
73+
the file compiles.
74+
- **bering-bearings** — the `polar`/`relative` tuples, direction symbols, and the
75+
`>cartesian`/`flip` generics were scattered across tasks. *Fixed* by bundling
76+
all the data and generic declarations into task 1; the per-class methods stay
77+
in their own tasks.
7978
- **boatswains-bilge** — task 5's `valve` tuple, `<valve>` constructor, and
80-
`is-open` slot are not declared; the tests reference `<valve>`/`is-open>>`, so
81-
tasks 1–4 cannot compile. (Tasks 1–4 themselves use a `test-pump` fixture
82-
defined inside the test file and are otherwise fine.)
83-
*Fix:* pre-ship the valve skeleton in the stub —
84-
`TUPLE: valve < disposable is-open ;`, a stubbed `<valve>`, and `M: valve
85-
dispose* drop ;` — so the file compiles; task 5 fills in the bodies.
79+
`is-open` slot were not declared; the tests reference `<valve>`/`is-open>>`, so
80+
tasks 1–4 could not compile. *Fixed* by pre-shipping the valve skeleton
81+
(`TUPLE: valve < disposable is-open ;`, a stubbed `<valve>`, and `M: valve
82+
dispose*`); task 5 fills in the bodies.
83+
84+
`factory-failsafe`, `dragons-descendants`, and `bering-bearings` now rely on a
85+
task-1 definition to compile (like `lasagna` and `role-playing-game`): the bare
86+
stub does not compile on its own, which `bin/check-accretive` recognises via its
87+
`ACCRETIVE_VIA_TASK1` list.
8688

8789
## Mode B — an early task's test called a later task's word (fixed)
8890

bin/check-accretive

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ MAPS = {
5050
"character-study": {"compare-chars":1,"size-of-char":2,"change-size-of-char":3,"type-of-char":4},
5151
"coordinate-choreography": {"translate-2d":1,"scale-2d":2,"compose-transformations":3,"apply-transformation":4,"transform-points":5},
5252
"currency-conversion": {"exchange-money":1,"get-change":2,"value-of-bills":3,"number-of-bills":4,"leftover-of-bills":5,"exchangeable-value":6,"safe-change":7,"cap-spend":8},
53-
"factory-failsafe": {"check-humidity":1,"check-temperature":2,"monitor":4,"monitor-batch":5},
53+
"dragons-descendants": {"<dragon>":1,"<fire-dragon>":2,"<ice-dragon>":3,"<volcano-dragon>":4,"age-dragon":5},
54+
"factory-failsafe": {"check-humidity":2,"check-temperature":3,"monitor":4,"monitor-batch":5},
5455
"ferry-schedule": {"make-date":1,"weekday-name":2,"leap?":3,"month-length":4,"add-days":5},
5556
"garden-gathering": {"open-garden":1,"list-registrations":1,"register":2,"release":3,"get-registration":4,"find-by-name":5},
5657
"high-school-sweetheart": {"cleanupname":1,"firstletter":2,"initial":3,"couple":4},
@@ -84,12 +85,13 @@ MAPS = {
8485
# bodies cannot be re-stubbed with a throw, and exercises without TASK: markers
8586
# have no prefixes). Mode A is still checked for them.
8687
MODEB_SKIP = {"signal-stencils", "telegraphers-tape", "bering-bearings",
87-
"boatswains-bilge", "dragons-descendants"}
88+
"boatswains-bilge"}
8889

8990
# The shipped stub does not make the test file compile, but the missing
9091
# definition is created in task 1, so the exercise is still accretive by the
9192
# implement-first-K-tasks rule (a student who does task 1 sees task 1 pass).
92-
ACCRETIVE_VIA_TASK1 = {"lasagna", "role-playing-game"}
93+
ACCRETIVE_VIA_TASK1 = {"lasagna", "role-playing-game", "factory-failsafe",
94+
"dragons-descendants", "bering-bearings"}
9395

9496
DEF_STARTERS = {":","::","M:","M::","TYPED:","TYPED::","MEMO:","MEMO::"}
9597

exercises/concept/bering-bearings/.docs/instructions.md

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,24 @@ Your job is to convert all three into a common cartesian `(x, y)`
2020
frame so the chart can be plotted. Bearings are degrees; `(0, 1)`
2121
is one nautical mile north, `(1, 0)` is one nautical mile east.
2222

23-
## 1. Cartesian for cardinal
23+
## 1. The data model, and cartesian for cardinal
2424

25-
Define a tuple `cardinal` with one slot, `direction`, holding
26-
one of `north`, `east`, `south`, `west` (declared with
27-
`SYMBOLS:`). Then declare a `GENERIC:` word
28-
`>cartesian ( direction -- x y )` and add an `M: cardinal`
29-
method that returns the unit-vector for the named direction.
25+
First lay out the pieces the whole exercise shares:
26+
27+
- Define three tuples: `cardinal` (one slot, `direction`), `polar`
28+
(slots `magnitude` and `bearing`), and `relative` (slots
29+
`distance` and `bearing`).
30+
- Declare the heading symbols with `SYMBOLS:`: `north`, `east`,
31+
`south`, `west`, `ahead`, `starboard`, `behind`, `port`.
32+
- Declare a dynamic variable `heading` with `SYMBOL:` (task 3 uses
33+
it).
34+
- Declare two generic words —
35+
`GENERIC: >cartesian ( direction -- x y )` and
36+
`GENERIC: flip ( direction -- direction' )`. You add their
37+
methods over the next tasks.
38+
39+
Then add the `M: cardinal` method of `>cartesian`, returning the
40+
unit-vector for the named direction.
3041

3142
```factor
3243
T{ cardinal { direction north } } >cartesian . .
@@ -37,9 +48,8 @@ T{ cardinal { direction north } } >cartesian . .
3748

3849
## 2. Cartesian for polar
3950

40-
Define a tuple `polar` with slots `magnitude` and `bearing`
41-
(degrees clockwise from north). Add an `M: polar` method to
42-
`>cartesian` that converts the polar form to `(x, y)`:
51+
Add an `M: polar` method to `>cartesian` that converts the polar
52+
form to `(x, y)`:
4353

4454
```
4555
x = magnitude * sin(bearing-in-radians)
@@ -54,17 +64,13 @@ T{ polar { magnitude 10 } { bearing 90 } } >cartesian . .
5464

5565
## 3. Cartesian for relative
5666

57-
Define a tuple `relative` with slots `distance` and `bearing`
58-
(one of the symbols `ahead`, `starboard`, `behind`, `port`).
59-
Add an `M: relative` method to `>cartesian`. The catch: a
60-
relative bearing is measured against the ship's *current
61-
heading*, which isn't part of the tuple.
62-
63-
Declare a dynamic variable `heading` (with `SYMBOL:`). The
64-
caller will set it inside a `with-variable` block. Your method
65-
reads it with `heading get`, adds the bearing offset
66-
(`ahead = 0`, `starboard = 90`, `behind = 180`, `port = 270`),
67-
and produces the cartesian point.
67+
Add an `M: relative` method to `>cartesian`. The catch: a relative
68+
bearing is measured against the ship's *current heading*, which
69+
isn't part of the tuple. Read the `heading` variable (declared in
70+
task 1) with `heading get`, add the bearing offset (`ahead = 0`,
71+
`starboard = 90`, `behind = 180`, `port = 270`), and produce the
72+
cartesian point. The caller sets `heading` inside a `with-variable`
73+
block.
6874

6975
```factor
7076
0 heading [
@@ -76,8 +82,8 @@ and produces the cartesian point.
7682

7783
## 4. Flip
7884

79-
Define a generic `flip ( direction -- direction' )` that returns
80-
the opposite direction.
85+
Add the methods of the `flip` generic (declared in task 1) so it
86+
returns the opposite direction.
8187

8288
- For `cardinal`: north ↔ south, east ↔ west.
8389
- For `polar`: add 180° to the bearing (modulo 360).

exercises/concept/bering-bearings/.meta/design.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,13 @@ fudge.
4242

4343
## Tasks ramp
4444

45-
1. `>cartesian` for `cardinal` — first method. Pure case-lookup.
45+
1. The data model + `>cartesian` for `cardinal` — define the
46+
three direction tuples, the direction symbols, the `heading`
47+
variable, and both generics (`>cartesian`, `flip`), then the
48+
first method (pure case-lookup). Bundling the declarations
49+
here keeps the exercise accretive — the test file references
50+
all three tuples and both generics, so they must exist once
51+
task 1 is done.
4652
2. `>cartesian` for `polar` — adds arithmetic, no ambient state.
4753
3. `>cartesian` for `relative` — adds the dynamic variable.
4854
4. `flip` — second generic, demonstrates that Factor doesn't
Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
USING: kernel ;
22
IN: bering-bearings
33

4-
! Define your tuples here.
4+
! Task 1: define the data model and the two generic words here:
5+
! - tuple cardinal (slot: direction); tuple polar (magnitude bearing);
6+
! tuple relative (distance bearing)
7+
! - SYMBOLS: north east south west ahead starboard behind port
8+
! - SYMBOL: heading
9+
! - GENERIC: >cartesian ( direction -- x y )
10+
! - GENERIC: flip ( direction -- direction' )
11+
! - the M: cardinal method of >cartesian
12+
! The polar/relative >cartesian methods (tasks 2-3) and the flip
13+
! methods (task 4) are added later.
514

6-
! Define `heading` as a dynamic variable here.
7-
8-
! Define `>cartesian` as a generic word with one method
9-
! per direction class.
10-
11-
! Define `flip` as a generic word with one method per
12-
! direction class.
13-
14-
! Define `add-bearings` here, using TYPED:: to type its
15-
! cartesian outputs: ( a b -- x: number y: number ).
15+
: add-bearings ( a b -- x y )
16+
"unimplemented" throw ;

exercises/concept/boatswains-bilge/.docs/instructions.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,13 @@ throws, the pump is released and the exception propagates.
6262

6363
## 5. A custom disposable: the valve
6464

65-
Define a brand-new disposable — a `valve` — to round out the
66-
toolkit.
65+
Round out the toolkit with a brand-new disposable — a `valve`.
66+
The tuple is declared for you:
67+
68+
```factor
69+
TUPLE: valve < disposable is-open ;
70+
```
6771

68-
- Declare a tuple `valve` that extends `disposable` and adds an
69-
`is-open` slot.
7072
- Define `<valve> ( -- valve )` to construct a fresh valve via
7173
`new-disposable`, with `is-open` set to `t`.
7274
- Implement `M: valve dispose*` to flip `is-open` to `f`.

exercises/concept/boatswains-bilge/boatswains-bilge/boatswains-bilge.factor

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,12 @@ IN: boatswains-bilge
1313
: risky-pump-out ( pump quot -- )
1414
"unimplemented" throw ;
1515

16-
! Task 5: define `valve` as a custom disposable, `<valve>` as its
17-
! constructor, and an `M: valve dispose*` method.
16+
! Task 5: the valve tuple is declared for you. Implement <valve>
17+
! (construct a fresh open valve) and M: valve dispose* (mark it closed).
18+
TUPLE: valve < disposable is-open ;
19+
20+
: <valve> ( -- valve )
21+
"unimplemented" throw ;
22+
23+
M: valve dispose*
24+
"unimplemented" throw ;

exercises/concept/dragons-descendants/.docs/instructions.md

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,27 @@ a name, colour, and age — but specialise in distinctive ways.
66
You'll build a small inheritance tree of dragon classes and a
77
single word that ages any descendant.
88

9-
## 1. The base class
9+
## 1. The dragon family
1010

11-
Define a tuple `dragon` with slots `name`, `color`, `age`, and
12-
a `<dragon>` constructor.
11+
Define the whole inheritance tree of tuple classes up front (their
12+
constructors come in the tasks that follow):
13+
14+
- `dragon` with slots `name`, `color`, `age`.
15+
- `fire-dragon`, a subclass of `dragon`, adding a `flame-temp` slot.
16+
- `ice-dragon`, another subclass of `dragon`, adding a `chill-temp`
17+
slot.
18+
- `volcano-dragon`, a subclass of `fire-dragon`, adding a
19+
`lava-volume` slot.
20+
21+
Then give `dragon` a `<dragon>` constructor.
1322

1423
```factor
1524
"Falkor" "white" 100 <dragon> name>> . ! => "Falkor"
1625
```
1726

1827
## 2. The fire breathers
1928

20-
Define `fire-dragon` as a subclass of `dragon` with one extra
21-
slot, `flame-temp`. Give it a `<fire-dragon>` constructor.
29+
Give `fire-dragon` a `<fire-dragon>` constructor.
2230

2331
```factor
2432
"Smaug" "red" 500 1200 <fire-dragon> flame-temp>> . ! => 1200
@@ -27,8 +35,7 @@ slot, `flame-temp`. Give it a `<fire-dragon>` constructor.
2735

2836
## 3. The ice breathers
2937

30-
Define `ice-dragon` as another subclass of `dragon`, with one
31-
extra slot `chill-temp` and a `<ice-dragon>` constructor.
38+
Give `ice-dragon` a `<ice-dragon>` constructor.
3239

3340
```factor
3441
"Frosty" "blue" 200 -40 <ice-dragon> chill-temp>> . ! => -40
@@ -37,9 +44,7 @@ extra slot `chill-temp` and a `<ice-dragon>` constructor.
3744

3845
## 4. The volcano dwellers
3946

40-
Define `volcano-dragon` as a subclass of `fire-dragon`, with
41-
one extra slot `lava-volume` and a `<volcano-dragon>`
42-
constructor.
47+
Give `volcano-dragon` a `<volcano-dragon>` constructor.
4348

4449
```factor
4550
"Vesuvius" "red" 1000 1500 99 <volcano-dragon> dragon? . ! => t

exercises/concept/dragons-descendants/.meta/design.md

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,21 @@ the `< disposable` syntax instead of pattern-matching it cold.
4646

4747
## Tasks ramp
4848

49-
1. **`<dragon>`** — declare the base class with three slots and
50-
the `boa` constructor. No inheritance yet.
51-
2. **`<fire-dragon>`** — first use of `<` — adds one slot. The
52-
constructor takes four arguments: three inherited, one new.
53-
3. **`<ice-dragon>`** — a *sibling* of `fire-dragon`. Reinforces
54-
that subclasses of the same parent are disjoint
55-
(`ice-dragon?` is `f` for a `fire-dragon`).
56-
4. **`<volcano-dragon>`***grandchild* via `< fire-dragon`.
57-
Demonstrates that inheritance is transitive: a
49+
1. **The dragon family** — declare all four tuple classes up
50+
front: the `dragon` base (three slots) and its descendants
51+
`fire-dragon` / `ice-dragon` (`< dragon`) and
52+
`volcano-dragon` (`< fire-dragon`), then the `<dragon>` `boa`
53+
constructor. Bundling the whole hierarchy here keeps the
54+
exercise accretive — the test file references every
55+
descendant's predicate and accessors, so they must all exist
56+
once task 1 is done.
57+
2. **`<fire-dragon>`** — the first descendant constructor. Takes
58+
four arguments: three inherited, one new.
59+
3. **`<ice-dragon>`** — a *sibling* constructor. Reinforces that
60+
subclasses of the same parent are disjoint (`ice-dragon?` is
61+
`f` for a `fire-dragon`).
62+
4. **`<volcano-dragon>`** — a *grandchild* constructor via
63+
`< fire-dragon`. Inheritance is transitive: a
5864
`volcano-dragon` satisfies `dragon?`, `fire-dragon?`, and
5965
`volcano-dragon?`.
6066
5. **`age-dragon`** — uses the parent's `change-age` accessor
Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
USING: kernel ;
22
IN: dragons-descendants
33

4-
! Task 1: TUPLE: dragon with slots `name`, `color`, `age`
5-
! and a constructor `<dragon> ( name color age -- dragon )`
4+
! Task 1: define the dragon tuple hierarchy here (dragon and its
5+
! descendants fire-dragon, ice-dragon, volcano-dragon — see the
6+
! instructions for each class's slots), then the <dragon> constructor
7+
! below. The descendant constructors follow in tasks 2-4.
68

7-
! Task 2: TUPLE: fire-dragon extending dragon, adding `flame-temp`
8-
! and `<fire-dragon> ( name color age flame-temp -- fd )`
9+
: <dragon> ( name color age -- dragon )
10+
"unimplemented" throw ;
911

10-
! Task 3: TUPLE: ice-dragon extending dragon, adding `chill-temp`
11-
! and `<ice-dragon> ( name color age chill-temp -- id )`
12+
: <fire-dragon> ( name color age flame-temp -- fd )
13+
"unimplemented" throw ;
1214

13-
! Task 4: TUPLE: volcano-dragon extending fire-dragon, adding `lava-volume`
14-
! and `<volcano-dragon> ( name color age flame-temp lava-volume -- vd )`
15+
: <ice-dragon> ( name color age chill-temp -- id )
16+
"unimplemented" throw ;
17+
18+
: <volcano-dragon> ( name color age flame-temp lava-volume -- vd )
19+
"unimplemented" throw ;
1520

1621
: age-dragon ( dragon -- )
1722
"unimplemented" throw ;

0 commit comments

Comments
 (0)