Skip to content

Commit 43c55d8

Browse files
committed
Add concept exercise valentines-day
1 parent ab58774 commit 43c55d8

File tree

13 files changed

+315
-0
lines changed

13 files changed

+315
-0
lines changed

config.json

+13
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,19 @@
8080
"concepts": [
8181
"pattern-matching-literals"
8282
]
83+
},
84+
{
85+
"slug": "valentines-day",
86+
"name": "Valentines Day",
87+
"uuid": "537d8df3-0b12-4dbe-aa86-65ae79c4de0e",
88+
"prerequisites": [
89+
"pattern-matching-literals",
90+
"numbers"
91+
],
92+
"status": "beta",
93+
"concepts": [
94+
"algebraic-data-types"
95+
]
8396
}
8497
],
8598
"practice": [
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Hints
2+
3+
## 1. Define the approval
4+
5+
- [This page][ADT] shows how to define an algebraic data type.
6+
7+
## 2. Define the cuisine
8+
9+
- [This page][ADT] shows how to define an algebraic data type.
10+
11+
## 3. Define the movie genres
12+
13+
- [This page][ADT] shows how to define an algebraic data type.
14+
15+
## 4. Define the activity
16+
17+
- [This section][ADT-with-data] of the same page shows how to define an algebraic data types with associated data.
18+
19+
## 5. Rate the activity
20+
21+
- The best way to execute logic based on the activity's value is to use [case expressions][case-expression].
22+
- Pattern matching an algebraic data type case provides access to its associated data.
23+
- To add an additional condition to a pattern, you can use a [guard][guards] inside a case.
24+
- If you want to catch all other possible values in one case, you can use the wildcard pattern `_`.
25+
26+
[ADT]: https://www.schoolofhaskell.com/school/starting-with-haskell/introduction-to-haskell/2-algebraic-data-types#enumeration-types
27+
[ADT-with-data]: https://www.schoolofhaskell.com/school/starting-with-haskell/introduction-to-haskell/2-algebraic-data-types#beyond-enumerations
28+
[case-expression]: https://www.schoolofhaskell.com/school/starting-with-haskell/introduction-to-haskell/2-algebraic-data-types#case-expessions
29+
[guards]: https://learnyouahaskell.github.io/syntax-in-functions.html#guards-guards
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Instructions
2+
3+
In this exercise, it's Valentine's day and you are planning what to do with your partner. Your partner has lots of ideas, and is asking you to rate the ideas, in order to find the best activity.
4+
5+
The following ideas are proposed by your partner:
6+
7+
- Playing a board game
8+
- Chill out
9+
- Watch a movie
10+
- Go to a restaurant
11+
- Take a walk
12+
13+
You have six tasks to help choose your Valentine's day activity.
14+
15+
## 1. Define the approval
16+
17+
For each idea your partner proposes, you respond with one of three options: yes, no or maybe.
18+
19+
Define the `Approval` algebraic data type to represent these options for the following three cases: `Yes`, `No` or `Maybe`.
20+
21+
## 2. Define the cuisines
22+
23+
Your partner has selected two possible restaurants: one based on Korean cuisine and the other based on Turkish cuisine.
24+
25+
Define the `Cuisine` algebraic data type to represent these restaurants as the following two cases: `Korean` or `Turkish`.
26+
27+
## 3. Define the movie genres
28+
29+
There are tons of movies to choose from, so to narrow things down, your partner also lists their preferred genre.
30+
31+
Define the `Genre` algebraic data type to represent the following genres cases: `Crime`, `Horror`, `Romance` or `Thriller`.
32+
33+
## 4. Define the activity
34+
35+
As mentioned, your partner has come up with five possible activities: playing a board game, chill out, watch a movie, go to a restaurant and taking a walk.
36+
37+
Define the `Activity` algebraic data type to represent these activity types:
38+
39+
- `BoardGame`: no associated data.
40+
- `Chill`: no associated data.
41+
- `Movie`: has its `Genre` as associated data.
42+
- `Restaurant`: has its `Cuisine` as associated data.
43+
- `Walk`: has an `Int` representing the number of kilometers to walk as associated data.
44+
45+
## 5. Rate the activity
46+
47+
Finally, you're ready to rate your partner's ideas. This is how you feel about your partner's idea:
48+
49+
- Playing a board game: no.
50+
- Chill out: no.
51+
- Watch a movie: yes if it is a romantic movie; otherwise, no.
52+
- Go to a restaurant: yes if the cuisine is Korean, maybe if it is Turkish.
53+
- Take a walk: yes if the walk is less than three kilometers; maybe if it is between three and five kilometers; otherwise, no.
54+
55+
Implement a function named `rateActivity` that takes an `Activity` value and returns the `Approval` based on the above sentiments. For example:
56+
57+
```haskell
58+
rateActivity (Restaurant Turkish)
59+
-- -> Maybe
60+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Introduction
2+
3+
An Algebraic Data Type (ADT) represents a fixed number of named cases. Each value of an ADT corresponds to exactly one of the named cases.
4+
5+
An ADT is defined using the `data` keyword, with cases separated by pipe (`|`) characters. If none of the cases have data associated with them the ADT is similar to what other languages usually refer to as an _enumeration_ (or _enum_).
6+
7+
```haskell
8+
data Season
9+
= Spring
10+
| Summer
11+
| Autumn
12+
| Winter
13+
```
14+
15+
Each case of an ADT can optionally have data associated with it, and different cases can have different types of data. When the case has data associated, a constructor is required.
16+
17+
```haskell
18+
data Number
19+
= NInt Int --'NInt' is the constructor for an Int Number.
20+
| NFloat Float --'NFloat' is the constructor for an Float Number.
21+
| Invalid --'Invalid' does not have data associated to it.
22+
```
23+
24+
Creating a value for a specific case can be done by referring to its name (e.g, `NInt 22`). As case names are just constructor functions, associated data can be passed as a regular function argument.
25+
26+
ADTs have _structural equality_, which means that two values for the same case and with the same (optional) data are equivalent.
27+
28+
While one can use `if/else` expressions to work with ADTs, the recommended way to work with them is through pattern matching using _case_ statement:
29+
30+
```haskell
31+
add1 :: Number -> String
32+
add1 number =
33+
case number of
34+
NInt i -> show (i + 1)
35+
NFloat f -> show (f + 1.0)
36+
Invalid -> error "Invalid input"
37+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Teaches the basics of defining data types, and we found that people usually learn best when they have to write things from scratch.
2+
Thus, the stub lacks the data type definitions for the tests.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"blurb": "Learn about algebraic data types by deciding what activity to surprise your partner with on Valentines Day.",
3+
"authors": [
4+
"pwadsworth"
5+
],
6+
"forked_from": [
7+
"fsharp/valentines-day"
8+
],
9+
"files": {
10+
"solution": [
11+
"src/ValentinesDay.hs",
12+
"package.yaml"
13+
],
14+
"test": [
15+
"test/Tests.hs"
16+
],
17+
"exemplar": [
18+
".meta/exemplar/src/ValentinesDay.hs"
19+
]
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Design
2+
3+
## Learning objectives
4+
5+
- Know what [Algebraic Data Types][ADT] (ADT) are.
6+
- Know how ADTs are different from enums.
7+
- Know how to define ADT, with and without data.
8+
- Know how to pattern match on ADTs using [case expressions][case-expression].
9+
10+
## Out of scope
11+
12+
- Recursive ADT.
13+
- Single type wrapper ADT.
14+
- Active patterns.
15+
- Adding members to ADT.
16+
- `function` pattern shorthand notation.
17+
18+
## Concepts
19+
20+
- `Algebraic Data Types`: know what ADTs are; know how ADTs are different from enums; know how to define an ADT, with and without data; know how to pattern match on ADTs.
21+
22+
## Prerequisites
23+
24+
- `basics`: defining functions and scoping and using integers.
25+
- `pattern-matching`: know how to do pattern matching.
26+
27+
[ADT]: https://www.schoolofhaskell.com/school/starting-with-haskell/introduction-to-haskell/2-algebraic-data-types#enumeration-types
28+
[case-expression]: https://www.schoolofhaskell.com/school/starting-with-haskell/introduction-to-haskell/2-algebraic-data-types#case-expessions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
name: valentines-day
2+
version: 1.0.0.0
3+
4+
dependencies:
5+
- base
6+
7+
library:
8+
exposed-modules: ValentinesDay
9+
source-dirs: src
10+
ghc-options: -Wall
11+
12+
tests:
13+
test:
14+
main: Tests.hs
15+
source-dirs: test
16+
dependencies:
17+
- valentines-day
18+
- hspec
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
module ValentinesDay (rateActivity, Approval (..), Cuisine (..), Genre (..), Activity (..)) where
2+
3+
data Approval
4+
= Yes
5+
| No
6+
| Maybe
7+
8+
data Cuisine
9+
= Korean
10+
| Turkish
11+
12+
data Genre
13+
= Crime
14+
| Horror
15+
| Romance
16+
| Thriller
17+
18+
data Activity
19+
= BoardGame
20+
| Chill
21+
| Movie Genre
22+
| Restaurant Cuisine
23+
| Walk Int
24+
25+
rateActivity :: Activity -> Approval
26+
rateActivity activity =
27+
case activity of
28+
Restaurant Korean -> Yes
29+
Restaurant Turkish -> Maybe
30+
Movie Romance -> Yes
31+
Movie _ -> No
32+
Walk kilometers
33+
| kilometers < 3 -> Yes
34+
| kilometers < 5 -> Maybe
35+
_ -> No
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: valentines-day
2+
version: 1.0.0.0
3+
4+
dependencies:
5+
- base
6+
7+
library:
8+
exposed-modules: ValentinesDay
9+
source-dirs: src
10+
ghc-options: -Wall
11+
12+
13+
tests:
14+
test:
15+
main: Tests.hs
16+
source-dirs: test
17+
dependencies:
18+
- valentines-day
19+
- hspec
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module ValentinesDay where
2+
3+
-- Define the function and required algebraic data types (ADT) below.
4+
5+
data Approval = ImplementApproval
6+
7+
data Cuisine = ImplementCuisine
8+
9+
data Genre = ImplementGenre
10+
11+
data Activity = ImplementActivity
12+
13+
rateActivity :: Activity -> Approval
14+
rateActivity activity = error "Implement rateActivity"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
resolver: lts-18.14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import Test.Hspec (describe, hspec, it)
2+
import ValentinesDay (Activity (..), Approval (..), Cuisine (..), Genre (..), rateActivity)
3+
4+
main :: IO ()
5+
main = hspec $
6+
describe "ValentinesDay" $ do
7+
it "chill rated no" $
8+
case rateActivity Chill of
9+
No -> True
10+
_ -> False
11+
it "board game rated no" $
12+
case rateActivity BoardGame of
13+
No -> True
14+
_ -> False
15+
it "crime movie rated no" $
16+
case rateActivity (Movie Crime) of
17+
No -> True
18+
_ -> False
19+
it "horror movie rated no" $
20+
case rateActivity (Movie Horror) of
21+
No -> True
22+
_ -> False
23+
it "romance movie rated yes" $
24+
case rateActivity (Movie Romance) of
25+
Yes -> True
26+
_ -> False
27+
it "thriller movie rated no" $
28+
case rateActivity (Movie Thriller) of
29+
No -> True
30+
_ -> False
31+
it "korean restaurant rated no" $
32+
case rateActivity (Restaurant Korean) of
33+
Yes -> True
34+
_ -> False
35+
it "turkish restaurant rated maybe" $
36+
case rateActivity (Restaurant Turkish) of
37+
Maybe -> True
38+
_ -> False

0 commit comments

Comments
 (0)