-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
328 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
*.beam | ||
*.ez | ||
build | ||
erl_crash.dump |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Help | ||
|
||
## Running the tests | ||
|
||
To run the tests, run the command `gleam test` from within the exercise directory. | ||
|
||
## Submitting your solution | ||
|
||
You can submit your solution using the `exercism submit src/pizza_pricing.gleam` command. | ||
This command will upload your solution to the Exercism website and print the solution page's URL. | ||
|
||
It's possible to submit an incomplete solution which allows you to: | ||
|
||
- See how others have completed the exercise | ||
- Request help from a mentor | ||
|
||
## Need to get help? | ||
|
||
If you'd like help solving the exercise, check the following pages: | ||
|
||
- The [Gleam track's documentation](https://exercism.org/docs/tracks/gleam) | ||
- The [Gleam track's programming category on the forum](https://forum.exercism.org/c/programming/gleam) | ||
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) | ||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) | ||
|
||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. | ||
|
||
To get help if you're having trouble, you can use one of the following resources: | ||
|
||
- [gleam.run](https://gleam.run/documentation/) is the gleam official documentation. | ||
- [Discord](https://discord.gg/Fm8Pwmy) is the discord channel. | ||
- [StackOverflow](https://stackoverflow.com/questions/tagged/gleam) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Hints | ||
|
||
## General | ||
|
||
- Try to split a problem into a base case and a recursive case. For example, let's say you want to count how many cookies are there in the cookie jar with a recursive approach. A base case is an empty jar - it has zero cookies. If the jar is not empty, then the number of cookies in the jar is equal to one cookie plus the number of cookies in the jar after removing one cookie. | ||
|
||
## 1. Define the pizza types and options | ||
|
||
- The `Pizza` type is a recursive type, with the `ExtraSauce` and `ExtraToppings` cases containing a `Pizza`. | ||
|
||
## 2. Calculate the price of pizza | ||
|
||
- To handle the `Pizza` type being a recursive type, define a recursive function. | ||
|
||
## 3. Calculate the price of an order | ||
|
||
- The exact length of the list can be pattern matched upon to determine if the additional fee should be applied. | ||
- Use tail recursion to avoid using too much memory when calculating the price of an order. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
# Pizza Pricing | ||
|
||
Welcome to Pizza Pricing on Exercism's Gleam Track. | ||
If you need help running the tests or submitting your code, check out `HELP.md`. | ||
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) | ||
|
||
## Introduction | ||
|
||
## Tail Call Optimisation | ||
|
||
Each time a function is called a new stack frame is created in memory to store the arguments and local variables of the function, and this stack frame is deallocated when the function returns. Because Gleam uses recursive function calls instead of a looping syntax this can result in a large amount of memory being used by these stack frames. | ||
|
||
To avoid this problem Gleam supports tail call optimisation, which allows the compiler to reuse the stack frame for the current function if a function call is the last thing the function does. This means that a function can call itself an infinite number of times without using any additional memory. | ||
|
||
Unoptimised recursive functions can often be rewritten into tail call optimised functions by using an _accumulator_. | ||
|
||
An accumulator is a variable that is passed along in addition to the data. It is used to pass the current state of the function's execution, until the base case is reached. | ||
|
||
Accumulators should be initialized by the function's author, not the function's user. To achieve this, declare two functions - a public function that takes just the necessary data as arguments and initializes the accumulator, and a private function that also takes an accumulator. | ||
|
||
```gleam | ||
// Count the length of a list without tail call optimisation | ||
pub fn count(list: List(String)) -> Int { | ||
case list { | ||
[] -> 0 | ||
[_, ..rest] -> { | ||
let amount = count(rest) // Non-tail recursive call | ||
amount + 1 | ||
} | ||
} | ||
} | ||
``` | ||
|
||
```gleam | ||
// Count the length of a list with tail call optimisation | ||
pub fn count(list: List(String)) -> Int { | ||
count_elements(list, 0) | ||
} | ||
fn count_elements(list: List(String), accumulator: Int) -> Int { | ||
case list { | ||
[] -> accumulator | ||
[_, ..rest] -> { | ||
let accumulator = accumulator + 1 | ||
count_elements(rest, accumulator) // Tail recursive call | ||
} | ||
} | ||
} | ||
``` | ||
|
||
## Instructions | ||
|
||
In this exercise you're working at a pizza place that delivers to customers. | ||
|
||
You offer three types of pizzas: | ||
|
||
- Margherita: \$7 | ||
- Caprese: \$9 | ||
- Formaggio: \$10 | ||
|
||
Customers can also choose two additional options for a small additional fee: | ||
|
||
1. Extra sauce: \$1 | ||
1. Extra toppings: \$2 | ||
|
||
When customers place an order, an additional fee is added if they only order one or two pizzas: | ||
|
||
- 1 pizza: \$3 | ||
- 2 pizzas: \$2 | ||
|
||
You have three tasks, each of which will work with pizzas and their price. | ||
|
||
## 1. Define the pizza types and options | ||
|
||
Define the `Pizza` custom type to represent the different types of pizzas and options: | ||
|
||
- `Margherita` | ||
- `Caprese` | ||
- `Formaggio` | ||
- `ExtraSauce` | ||
- `ExtraToppings` | ||
|
||
`ExtraSauce` and `ExtraToppings` should wrap the `Pizza` type. | ||
|
||
## 2. Calculate the price of pizza | ||
|
||
Implement the `pizza_price` function to calculate a pizza's price: | ||
|
||
```gleam | ||
pizza_price(Caprese) | ||
// -> 9 | ||
``` | ||
|
||
## 3. Calculate the price of an order | ||
|
||
Implement the `order_price` function to calculate a pizza order's price: | ||
|
||
```gleam | ||
order_price([Margherita, Formaggio]) | ||
// -> 19 | ||
``` | ||
|
||
## Source | ||
|
||
### Created by | ||
|
||
- @lpil |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
name = "pizza_pricing" | ||
version = "0.1.0" | ||
|
||
[dependencies] | ||
gleam_bitwise = "~> 1.2" | ||
gleam_otp = "~> 0.7 or ~> 1.0" | ||
gleam_stdlib = "~> 0.32 or ~> 1.0" | ||
simplifile = "~> 1.0" | ||
gleam_erlang = ">= 0.25.0 and < 1.0.0" | ||
|
||
[dev-dependencies] | ||
exercism_test_runner = "~> 1.4" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# This file was generated by Gleam | ||
# You typically do not need to edit this file | ||
|
||
packages = [ | ||
{ name = "argv", version = "1.0.1", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "A6E9009E50BBE863EB37D963E4315398D41A3D87D0075480FC244125808F964A" }, | ||
{ name = "exercism_test_runner", version = "1.7.0", build_tools = ["gleam"], requirements = ["argv", "gap", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_stdlib", "simplifile"], otp_app = "exercism_test_runner", source = "hex", outer_checksum = "2FC1BADB19BEC2AE77BFD2D3A606A014C85412A7B874CAFC4BA8CF04B0B257CD" }, | ||
{ name = "gap", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib"], otp_app = "gap", source = "hex", outer_checksum = "2EE1B0A17E85CF73A0C1D29DA315A2699117A8F549C8E8D89FA8261BE41EDEB1" }, | ||
{ name = "glance", version = "0.8.2", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "ACF09457E8B564AD7A0D823DAFDD326F58263C01ACB0D432A9BEFDEDD1DA8E73" }, | ||
{ name = "gleam_bitwise", version = "1.3.1", build_tools = ["gleam"], requirements = [], otp_app = "gleam_bitwise", source = "hex", outer_checksum = "B36E1D3188D7F594C7FD4F43D0D2CE17561DE896202017548578B16FE1FE9EFC" }, | ||
{ name = "gleam_community_ansi", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4" }, | ||
{ name = "gleam_community_colour", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "A49A5E3AE8B637A5ACBA80ECB9B1AFE89FD3D5351FF6410A42B84F666D40D7D5" }, | ||
{ name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" }, | ||
{ name = "gleam_json", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "8B197DD5D578EA6AC2C0D4BDC634C71A5BCA8E7DB5F47091C263ECB411A60DF3" }, | ||
{ name = "gleam_otp", version = "0.10.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B" }, | ||
{ name = "gleam_stdlib", version = "0.36.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4" }, | ||
{ name = "glexer", version = "0.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "4484942A465482A0A100936E1E5F12314DB4B5AC0D87575A7B9E9062090B96BE" }, | ||
{ name = "simplifile", version = "1.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "EB9AA8E65E5C1E3E0FDCFC81BC363FD433CB122D7D062750FFDF24DE4AC40116" }, | ||
{ name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" }, | ||
] | ||
|
||
[requirements] | ||
exercism_test_runner = { version = "~> 1.4" } | ||
gleam_bitwise = { version = "~> 1.2" } | ||
gleam_erlang = { version = ">= 0.25.0 and < 1.0.0"} | ||
gleam_otp = { version = "~> 0.7 or ~> 1.0" } | ||
gleam_stdlib = { version = "~> 0.32 or ~> 1.0" } | ||
simplifile = { version = "~> 1.0" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
pub type Pizza { | ||
Margherita | ||
Caprese | ||
Formaggio | ||
ExtraSauce(Pizza) | ||
ExtraToppings(Pizza) | ||
} | ||
|
||
pub fn order_price(order: List(Pizza)) -> Int { | ||
subtotal(order) + fee(order) | ||
} | ||
|
||
fn subtotal(order: List(Pizza)) -> Int { | ||
subtotal_iter(order, 0) | ||
} | ||
|
||
fn subtotal_iter(order: List(Pizza), acc: Int) -> Int { | ||
case order { | ||
[] -> acc | ||
[pizza, ..order] -> subtotal_iter(order, acc + pizza_price(pizza)) | ||
} | ||
} | ||
|
||
pub fn pizza_price(pizza: Pizza) -> Int { | ||
pizza_price_iter(pizza, 0) | ||
} | ||
|
||
pub fn pizza_price_iter(pizza: Pizza, acc: Int) -> Int { | ||
case pizza { | ||
Margherita -> acc + 7 | ||
Caprese -> acc + 9 | ||
Formaggio -> acc + 10 | ||
ExtraSauce(p) -> pizza_price_iter(p, acc + 1) | ||
ExtraToppings(p) -> pizza_price_iter(p, acc + 2) | ||
} | ||
} | ||
|
||
fn fee(order: List(Pizza)) -> Int { | ||
case order { | ||
[_] -> 3 | ||
[_, _] -> 2 | ||
_ -> 0 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import exercism/should | ||
import exercism/test_runner | ||
import gleam/list | ||
import pizza_pricing.{Caprese, ExtraSauce, ExtraToppings, Formaggio, Margherita} | ||
|
||
pub fn main() { | ||
test_runner.main() | ||
} | ||
|
||
pub fn price_for_pizza_margherita_test() { | ||
pizza_pricing.pizza_price(Margherita) | ||
|> should.equal(7) | ||
} | ||
|
||
pub fn price_for_pizza_formaggio_test() { | ||
pizza_pricing.pizza_price(Formaggio) | ||
|> should.equal(10) | ||
} | ||
|
||
pub fn price_for_pizza_caprese_test() { | ||
pizza_pricing.pizza_price(Caprese) | ||
|> should.equal(9) | ||
} | ||
|
||
pub fn price_for_pizza_margherita_with_extra_sauce_test() { | ||
pizza_pricing.pizza_price(ExtraSauce(Margherita)) | ||
|> should.equal(8) | ||
} | ||
|
||
pub fn price_for_pizza_caprese_with_extra_toppings_test() { | ||
pizza_pricing.pizza_price(ExtraToppings(Caprese)) | ||
|> should.equal(11) | ||
} | ||
|
||
pub fn price_for_pizza_formaggio_with_extra_sauce_and_toppings_test() { | ||
pizza_pricing.pizza_price(ExtraSauce(ExtraToppings(Caprese))) | ||
|> should.equal(12) | ||
} | ||
|
||
pub fn price_for_pizza_caprese_with_extra_sauce_and_toppings_test() { | ||
pizza_pricing.pizza_price(ExtraToppings(ExtraSauce(Formaggio))) | ||
|> should.equal(13) | ||
} | ||
|
||
pub fn order_price_for_no_pizzas_test() { | ||
pizza_pricing.order_price([]) | ||
|> should.equal(0) | ||
} | ||
|
||
pub fn order_price_for_single_pizza_caprese_test() { | ||
pizza_pricing.order_price([Caprese]) | ||
|> should.equal(12) | ||
} | ||
|
||
pub fn order_price_for_single_pizza_formaggio_with_extra_sauce_test() { | ||
pizza_pricing.order_price([ExtraSauce(Formaggio)]) | ||
|> should.equal(14) | ||
} | ||
|
||
pub fn order_price_for_one_pizza_margherita_and_one_pizza_caprese_with_extra_toppings_test() { | ||
pizza_pricing.order_price([Margherita, ExtraToppings(Caprese)]) | ||
|> should.equal(20) | ||
} | ||
|
||
pub fn order_price_for_very_large_order_test() { | ||
pizza_pricing.order_price([ | ||
Margherita, | ||
ExtraSauce(Margherita), | ||
Caprese, | ||
ExtraToppings(Caprese), | ||
Formaggio, | ||
ExtraSauce(Formaggio), | ||
ExtraToppings(ExtraSauce(Formaggio)), | ||
ExtraToppings(ExtraSauce(Formaggio)), | ||
]) | ||
|> should.equal(82) | ||
} | ||
|
||
pub fn order_price_for_gigantic_order_test() { | ||
Margherita | ||
|> list.repeat(10_000_000) | ||
|> pizza_pricing.order_price | ||
|> should.equal(70_000_000) | ||
} |