Skip to content

Commit 45f153b

Browse files
currency-conversion cars-assemble log-levels (#177)
We add three concept exercises, covering mathematics, `cond` and string handling.
1 parent c1a0dc0 commit 45f153b

28 files changed

Lines changed: 905 additions & 0 deletions

config.json

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,44 @@
5252
"stack-effect"
5353
],
5454
"status": "wip"
55+
},
56+
{
57+
"slug": "currency-conversion",
58+
"name": "Currency Conversion",
59+
"uuid": "380a2d4f-ea48-47a1-94f1-fc8ec0561136",
60+
"concepts": [
61+
"numbers"
62+
],
63+
"prerequisites": [
64+
"stack-effect"
65+
],
66+
"status": "wip"
67+
},
68+
{
69+
"slug": "cars-assemble",
70+
"name": "Cars, Assemble!",
71+
"uuid": "e5e68b1a-5445-4251-a56b-6a40fab662ed",
72+
"concepts": [
73+
"conditionals"
74+
],
75+
"prerequisites": [
76+
"booleans",
77+
"numbers"
78+
],
79+
"status": "wip"
80+
},
81+
{
82+
"slug": "log-levels",
83+
"name": "Log Levels",
84+
"uuid": "2e436217-a007-438e-b553-451e10d9c459",
85+
"concepts": [
86+
"strings"
87+
],
88+
"prerequisites": [
89+
"stack-effect",
90+
"conditionals"
91+
],
92+
"status": "wip"
5593
}
5694
],
5795
"practice": [
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Hints
2+
3+
## General
4+
5+
- `cond` in [`combinators`][combinators] is the cleanest way to map a
6+
speed to a success rate.
7+
- The arithmetic words live in [`math`][math]; the float-to-integer
8+
helpers `floor` and `>integer` live in
9+
[`math.functions`][math.functions] and `math` respectively.
10+
11+
## 1. Calculate the success rate
12+
13+
- A `cond` clause is `{ [ predicate ] [ body ] }`. Each predicate
14+
inspects the speed but should leave the stack as it found it
15+
(a `dup``<test>` does that). The body usually starts with `drop`.
16+
- Order matters: check `zero?` before `4 <=`, because `0 4 <=` is `t`.
17+
- Use a final entry without a predicate as the default for speed `10`.
18+
19+
## 2. Calculate the production rate per hour
20+
21+
- Define `base-speed` as a `CONSTANT:` near the top of the file (just
22+
like `expected-bake-time` in `lasagna`).
23+
- Compute `base-speed * speed * success-rate`. One option is to use
24+
`bi` from `kernel`: it runs two quotations on the same input and
25+
leaves both results on the stack.
26+
27+
## 3. Calculate the number of working items produced per minute
28+
29+
- Divide the hourly rate by 60.
30+
- Use `floor` to drop the fractional part, then `>integer` to convert
31+
the float result into an integer.
32+
33+
[math]: https://docs.factorcode.org/content/vocab-math.html
34+
[math.functions]: https://docs.factorcode.org/content/vocab-math.functions.html
35+
[combinators]: https://docs.factorcode.org/content/vocab-combinators.html
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Instructions
2+
3+
In this exercise you'll be writing code to analyze the production of
4+
an assembly line in a car factory. The assembly line's speed can range
5+
from `0` (off) to `10` (maximum).
6+
7+
At its lowest non-zero speed (`1`), `221` cars are produced each hour.
8+
The production increases linearly with the speed, so at speed `4` the
9+
line produces `4 * 221 = 884` cars per hour. However, higher speeds
10+
increase the likelihood that faulty cars are produced, which then
11+
have to be discarded.
12+
13+
You have three tasks. Each takes a single integer parameter — the
14+
speed of the assembly line — off the stack.
15+
16+
## 1. Calculate the success rate
17+
18+
Define `success-rate` to return the probability of an item being
19+
produced without error:
20+
21+
- `0`: `0.0`
22+
- `1` to `4`: `1.0`
23+
- `5` to `8`: `0.9`
24+
- `9`: `0.8`
25+
- `10`: `0.77`
26+
27+
```factor
28+
10 success-rate .
29+
! => 0.77
30+
```
31+
32+
## 2. Calculate the production rate per hour
33+
34+
Define `production-rate-per-hour` to return the assembly line's
35+
production rate per hour, taking the success rate into account.
36+
37+
You'll need to define `base-speed` first, the constant `221`.
38+
39+
```factor
40+
6 production-rate-per-hour .
41+
! => 1193.4
42+
```
43+
44+
The value returned is floating-point.
45+
46+
## 3. Calculate the number of working items produced per minute
47+
48+
Define `working-items-per-minute` to return how many working cars are
49+
produced per minute. The result is an integer — partial cars are not
50+
counted.
51+
52+
```factor
53+
6 working-items-per-minute .
54+
! => 19
55+
```
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Introduction
2+
3+
This exercise introduces conditionals — choosing between two or more
4+
courses of action based on a value. It builds on the booleans you met
5+
in [Annalyn's Infiltration][annalyns] and the integer arithmetic from
6+
[Currency Conversion][currency-conversion].
7+
8+
## Comparison words
9+
10+
These all live in [`math`][math] (and `kernel` for `=`):
11+
12+
```
13+
= ( x y -- ? ) ! equal
14+
< ( x y -- ? ) ! less than
15+
<= ( x y -- ? ) ! less than or equal
16+
> ( x y -- ? ) ! greater than
17+
>= ( x y -- ? ) ! greater than or equal
18+
```
19+
20+
```factor
21+
3 3 = . ! => t
22+
2 3 < . ! => t
23+
3 3 <= . ! => t
24+
```
25+
26+
## `if`, `when`, `unless`
27+
28+
`if` (in [`kernel`][kernel]) takes a boolean and two quotations. It
29+
runs the first quotation when the boolean is truthy and the second
30+
when it is falsy:
31+
32+
```
33+
if ( ? then-quot else-quot -- )
34+
```
35+
36+
```factor
37+
: abs ( x -- y ) dup 0 < [ neg ] [ ] if ;
38+
```
39+
40+
`when` runs its quotation only when the boolean is truthy; `unless`
41+
only when it is falsy:
42+
43+
```
44+
when ( ? quot -- )
45+
unless ( ? quot -- )
46+
```
47+
48+
## `cond`
49+
50+
When you have several alternative actions to choose between, `cond`
51+
(in [`combinators`][combinators]) is the natural fit. It takes an
52+
array of `{ predicate body }` pairs and runs the body of the first
53+
predicate that yields a truthy value:
54+
55+
```factor
56+
USING: combinators ;
57+
58+
: classify ( n -- label )
59+
{
60+
{ [ dup 0 < ] [ drop "negative" ] }
61+
{ [ dup 0 = ] [ drop "zero" ] }
62+
[ drop "positive" ]
63+
} cond ;
64+
```
65+
66+
A few details worth noting:
67+
68+
- The pairs are tried in order. The first match wins.
69+
- An entry without a predicate (just a single quotation) at the end
70+
acts as the default.
71+
- Each predicate inspects the input but should leave the data stack
72+
the way it found it — `dup ... <test>` is the usual idiom.
73+
- The body of the chosen pair receives the same stack the predicate
74+
saw, so it usually starts by `drop`ping the input and pushing the
75+
result.
76+
77+
[annalyns]: https://exercism.org/tracks/factor/exercises/annalyns-infiltration
78+
[currency-conversion]: https://exercism.org/tracks/factor/exercises/currency-conversion
79+
[math]: https://docs.factorcode.org/content/vocab-math.html
80+
[kernel]: https://docs.factorcode.org/content/vocab-kernel.html
81+
[combinators]: https://docs.factorcode.org/content/vocab-combinators.html
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Source
2+
3+
Forked from the Julia track's ["Cars, Assemble!" exercise][julia-source].
4+
5+
[julia-source]: https://github.com/exercism/julia/tree/main/exercises/concept/cars-assemble
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"authors": [
3+
"keiravillekode"
4+
],
5+
"files": {
6+
"solution": [
7+
"cars-assemble/cars-assemble.factor"
8+
],
9+
"test": [
10+
"cars-assemble/cars-assemble-tests.factor"
11+
],
12+
"exemplar": [
13+
".meta/exemplar.factor"
14+
]
15+
},
16+
"forked_from": [
17+
"julia/cars-assemble"
18+
],
19+
"blurb": "Learn about conditionals in Factor by analyzing the production of an assembly line."
20+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Design
2+
3+
## Goal
4+
5+
Introduce Factor's conditional combinators by mapping a discrete input
6+
(speed) onto a discrete output (success rate).
7+
8+
## Learning objectives
9+
10+
- Use comparison words `=`, `<`, `<=`, `>`, `>=` from `math` and `kernel`.
11+
- Use `if`, `when`, `unless` to choose between two quotations.
12+
- Use `cond` from `combinators` for a chained "first matching predicate"
13+
selection.
14+
- Combine the `dup``drop` pattern with `cond` to inspect a value
15+
without consuming it.
16+
17+
## Out of scope
18+
19+
- `case` from `combinators` for value-based dispatch.
20+
- Multimethods, `GENERIC:`.
21+
- Arithmetic combinators like `bi` are introduced incidentally for
22+
task 2; deeper coverage belongs in a later exercise.
23+
24+
## Concepts
25+
26+
- `conditionals`: `if`, `when`, `unless`, and especially `cond`.
27+
28+
## Prerequisites
29+
30+
- `booleans` — taught in `annalyns-infiltration`.
31+
- `numbers` — taught in `currency-conversion`.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
USING: combinators kernel math math.functions ;
2+
IN: cars-assemble
3+
4+
CONSTANT: base-speed 221
5+
6+
: success-rate ( speed -- rate )
7+
{
8+
{ [ dup zero? ] [ drop 0.0 ] }
9+
{ [ dup 4 <= ] [ drop 1.0 ] }
10+
{ [ dup 8 <= ] [ drop 0.9 ] }
11+
{ [ dup 9 = ] [ drop 0.8 ] }
12+
[ drop 0.77 ]
13+
} cond ;
14+
15+
: production-rate-per-hour ( speed -- rate )
16+
[ base-speed * ] [ success-rate ] bi * ;
17+
18+
: working-items-per-minute ( speed -- count )
19+
production-rate-per-hour 60 / floor >integer ;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
USING: cars-assemble tools.test ;
2+
IN: cars-assemble.tests
3+
4+
! TASK: 1 success-rate
5+
{ 0.0 } [ 0 success-rate ] unit-test
6+
{ 1.0 } [ 1 success-rate ] unit-test
7+
{ 1.0 } [ 4 success-rate ] unit-test
8+
{ 0.9 } [ 5 success-rate ] unit-test
9+
{ 0.8 } [ 9 success-rate ] unit-test
10+
{ 0.77 } [ 10 success-rate ] unit-test
11+
12+
! TASK: 2 production-rate-per-hour
13+
{ 0.0 } [ 0 production-rate-per-hour ] unit-test
14+
{ 221.0 } [ 1 production-rate-per-hour ] unit-test
15+
{ 884.0 } [ 4 production-rate-per-hour ] unit-test
16+
{ 994.5 } [ 5 production-rate-per-hour ] unit-test
17+
{ 1193.4 } [ 6 production-rate-per-hour ] unit-test
18+
{ 1591.2 } [ 9 production-rate-per-hour ] unit-test
19+
{ 1701.7 } [ 10 production-rate-per-hour ] unit-test
20+
21+
! TASK: 3 working-items-per-minute
22+
{ 0 } [ 0 working-items-per-minute ] unit-test
23+
{ 14 } [ 4 working-items-per-minute ] unit-test
24+
{ 19 } [ 6 working-items-per-minute ] unit-test
25+
{ 28 } [ 10 working-items-per-minute ] unit-test
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
USING: kernel ;
2+
IN: cars-assemble
3+
4+
! Define base-speed.
5+
6+
: success-rate ( speed -- rate )
7+
"unimplemented" throw ;
8+
9+
: production-rate-per-hour ( speed -- rate )
10+
"unimplemented" throw ;
11+
12+
: working-items-per-minute ( speed -- count )
13+
"unimplemented" throw ;

0 commit comments

Comments
 (0)