Skip to content

Commit 211c86b

Browse files
authored
space-age: Add Approaches for Space Age (#1144)
1 parent 2596909 commit 211c86b

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"introduction": {
3+
"authors": [
4+
"MatthijsBlom"
5+
]
6+
},
7+
"approaches": []
8+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Introduction
2+
3+
Suppose you are on Mercury.
4+
The [orbital period][wikipedia-orbital-period] of Mercury is approximately one fourth of an Earth year.
5+
This means that in one Earth year, Mercury will complete about four whole orbits around the sun.
6+
As a consequence, your 'age' on Mercury is about four times your age on Earth.
7+
8+
More generally, your 'age' on a certain planet is the number of seconds since your birth, divided by the number of seconds it takes the planet to orbit the sun once.
9+
10+
The various planets' orbital periods as compared to the Earth's are given.
11+
To convert them from _Earth years_ per orbit to _seconds_ per orbit you need to multiply this by the number of seconds in one Earth year.
12+
13+
14+
## Approach: give meaningful names to important values
15+
16+
```haskell
17+
ageOn :: Planet -> Float -> Float
18+
ageOn planet seconds = seconds / (periodInEarthYears * secondsPerEarthYear)
19+
where
20+
secondsPerEarthYear = 60 * 60 * 24 * 365.25
21+
22+
periodInEarthYears = case planet of
23+
Mercury -> 0.2408467
24+
Venus -> 0.61519726
25+
Earth -> 1
26+
Mars -> 1.8808158
27+
Jupiter -> 11.862615
28+
Saturn -> 29.447498
29+
Uranus -> 84.016846
30+
Neptune -> 164.79132
31+
```
32+
33+
This approach uses a `case` expression to choose the relevant orbital period.
34+
Also a `where` clause is used to give names to important values.
35+
This tends to greatly improve readability.
36+
37+
38+
## General guidance
39+
40+
### `where` clauses are your friend!
41+
42+
Giving meaningful names to subexpressions can do wonders for code readability.
43+
`let` expressions allow the same.
44+
Being expressions – which `where` clauses aren't – `let` expressions are a bit more flexible in their use.
45+
However, `where` clauses list the local definitions _after_ the main expression.
46+
This allows you to paint the broad strokes of your strategy first, and to fill in the details later.
47+
This is so convenient that it amply compensates for `where` clauses not being expressions.
48+
49+
More on `where` and `let` elsewhere:
50+
51+
- Haskell Wiki: [Let vs. Where][haskellwiki-let-vs-where]
52+
- Haskell Wikibook:
53+
- [`where` clauses][wikibook-where]
54+
- [`let` bindings][wikibook-let]
55+
- [`let` and `where` revisited][wikibook-let-vs-where]
56+
57+
58+
### `case` expressions are also your friend!
59+
60+
Many beginning Haskellers write code like
61+
62+
```haskell
63+
ageOn planet seconds
64+
| planet == Mercury = _
65+
| planet == Venus = _
66+
| {- etc. -} = _
67+
```
68+
69+
Using guards like this is an [anti-pattern][wikipedia-anti-pattern].
70+
Pattern-match instead, for example using a `case` expression:
71+
72+
```haskell
73+
ageOn planet seconds =
74+
case planet of
75+
Mercury -> _
76+
Venus -> _
77+
{- etc. -} -> _
78+
```
79+
80+
Pattern matching is a fundamental concept in Haskell, but this document is too short to be able to fully explain it.
81+
Please consult your other learning resources.
82+
The track docs include an article on [Haskell learning resources][learning-resources].
83+
84+
Pattern matching with `case` has benefits over using guards:
85+
86+
- `case` expressions are _expressions_.
87+
Therefore as pieces of code they are very easy to move around during code composition.
88+
You can give them names (e.g. in a `where` clause) and also pass them to functions as arguments.
89+
- The compiler is able to check that you handle all possible cases.
90+
If you overlook some cases and use guards, the compiler will not help you.
91+
But if you are pattern matching it will!
92+
- When you use pattern matching, the compiler can use its understanding of your code to apply code transformations that improve performance.
93+
94+
95+
[learning-resources]:
96+
https://exercism.org/docs/tracks/haskell/learning
97+
"How to learn Haskell"
98+
99+
100+
[haskellwiki-let-vs-where]:
101+
https://wiki.haskell.org/Let_vs._Where
102+
"Haskell Wiki: Let vs. Where"
103+
[wikibook-let-vs-where]:
104+
https://en.wikibooks.org/wiki/Haskell/More_on_functions#let_and_where_revisited
105+
"Haskell Wikibook: let and where revisited"
106+
[wikibook-let]:
107+
https://en.wikibooks.org/wiki/Haskell/Next_steps#let_bindings
108+
"Haskell Wikibook: let bindings"
109+
[wikibook-where]:
110+
https://en.wikibooks.org/wiki/Haskell/Variables_and_functions#where_clauses
111+
"Haskell Wikibook: where clauses"
112+
[wikipedia-anti-pattern]:
113+
https://en.wikipedia.org/wiki/Anti-pattern
114+
"Wikipedia: Anti-pattern"
115+
[wikipedia-orbital-period]:
116+
https://en.wikipedia.org/wiki/Orbital_period
117+
"Wikipedia: Orbital period"

0 commit comments

Comments
 (0)