Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lucas numbers: swap steps to avoid infinite recursion bugs #1512

Merged
merged 1 commit into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions exercises/concept/lucas-numbers/.docs/hints.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@
- Use the built-in [(linked) list type][list].
- Use the built-in [`Stream`][stream] module functions to create a stream

## 1. Generate the base cases
## 1. Catch bad arguments

- Use a [guard][guards] to catch the cases when an integer isn't passed as an argument to `generate/1`.

## 2. Generate the base cases

- You can use multiple [function clauses][multiple-fn-clauses] and [pattern-matching][pattern-matching] to create the base case functions.

## 2. Create the generalized case
## 3. Create the generalized case

- Use the [`Stream.iterate/2`][stream-iterate] function to generate a sequence of numbers, with the next being created from the previous.
- The starting numbers are `2` then `1`, which you can pass in together using a tuple to make a pair `{2, 1}`
- Make sure the next number is the sum of the two numbers previous to it.
- To evaluate the stream to a list, use an [`Enum`][enum] function.

## 3. Catch bad arguments

- Use a [guard][guards] to catch the cases when an integer isn't passed as an argument to `generate/1`.

[enum]: https://hexdocs.pm/elixir/Enum.html#content
[guards]: https://hexdocs.pm/elixir/patterns-and-guards.html#guards
[list]: https://hexdocs.pm/elixir/lists-and-tuples.html#linked-lists
Expand Down
24 changes: 12 additions & 12 deletions exercises/concept/lucas-numbers/.docs/instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,18 @@

You are a huge fan of the [Numberphile Youtube channel](https://www.youtube.com/watch?v=PeUbRXnbmms) and you just saw a cool video about the _Lucas Number Sequence_. You want to create this sequence using Elixir.

While designing your function, you want to make use of _lazy evaluation_, so that you can generate as many numbers as you want, but only if you need to -- So you decide to use a stream:
While designing your function, you want to make use of _lazy evaluation_, so that you can generate as many numbers as you want, but only if you need to -- So you decide to use a stream.

## 1. Generate the base cases
## 1. Catch bad arguments

Add a guard clause to raise an error if a non-integer or an integer less than 1 is used to generate the sequence. Doing this as the first step will prevent infinite recursion bugs in later steps.

```elixir
LucasNumbers.generate("Hello World")
# => ** (ArgumentError) count must be specified as an integer >= 1
```

## 2. Generate the base cases

You know that the sequence has two starting numbers which don't follow the same rule. Write two base case clauses to return these numbers:

Expand All @@ -16,7 +25,7 @@ LucasNumbers.generate(2)
# => [2, 1]
```

## 2. Create the generalized case
## 3. Create the generalized case

For any sequence longer than 2, you know that you need to add the previous two numbers to get the next number and so on. Write the generalized case.

Expand All @@ -27,12 +36,3 @@ LucasNumbers.generate(3)
LucasNumbers.generate(4)
# => [2, 1, 3, 4]
```

## 3. Catch bad arguments

Later, you find someone is using your function and having problems because they are using incorrect arguments. Add a guard clause to raise an error if a non-integer or an integer less than 1 is used to generate the sequence:

```elixir
LucasNumbers.generate("Hello World")
# => ** (ArgumentError) count must be specified as an integer >= 1
```
48 changes: 24 additions & 24 deletions exercises/concept/lucas-numbers/test/lucas_numbers_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,68 +2,82 @@ defmodule LucasNumbersTest do
use ExUnit.Case

@tag task_id: 1
test "catch incorrect non-integer arguments" do
assert_raise ArgumentError, "count must be specified as an integer >= 1", fn ->
LucasNumbers.generate("Hello world!")
end
end

@tag task_id: 1
test "catch incorrect integer arguments" do
assert_raise ArgumentError, "count must be specified as an integer >= 1", fn ->
LucasNumbers.generate(-1)
end
end

@tag task_id: 2
test "generates a sequence of length 1" do
assert LucasNumbers.generate(1) == [2]
end

@tag task_id: 1
@tag task_id: 2
test "generates a sequence of length 2" do
assert LucasNumbers.generate(2) == [2, 1]
end

@tag task_id: 2
@tag task_id: 3
test "generates a sequence of length 3" do
assert LucasNumbers.generate(3) == [2, 1, 3]
end

@tag task_id: 2
@tag task_id: 3
test "generates a sequence of length 4" do
assert LucasNumbers.generate(4) == [2, 1, 3, 4]
end

@tag task_id: 2
@tag task_id: 3
test "generates a sequence of length 5" do
sequence = [2, 1, 3, 4, 7]

assert LucasNumbers.generate(5) == sequence
end

@tag task_id: 2
@tag task_id: 3
test "generates a sequence of length 6" do
sequence = [2, 1, 3, 4, 7, 11]

assert LucasNumbers.generate(6) == sequence
end

@tag task_id: 2
@tag task_id: 3
test "generates a sequence of length 7" do
sequence = [2, 1, 3, 4, 7, 11, 18]

assert LucasNumbers.generate(7) == sequence
end

@tag task_id: 2
@tag task_id: 3
test "generates a sequence of length 8" do
sequence = [2, 1, 3, 4, 7, 11, 18, 29]

assert LucasNumbers.generate(8) == sequence
end

@tag task_id: 2
@tag task_id: 3
test "generates a sequence of length 9" do
sequence = [2, 1, 3, 4, 7, 11, 18, 29, 47]

assert LucasNumbers.generate(9) == sequence
end

@tag task_id: 2
@tag task_id: 3
test "generates a sequence of length 10" do
sequence = [2, 1, 3, 4, 7, 11, 18, 29, 47, 76]

assert LucasNumbers.generate(10) == sequence
end

@tag task_id: 2
@tag task_id: 3
test "generates a sequence of length 25" do
sequence = [
2,
Expand Down Expand Up @@ -95,18 +109,4 @@ defmodule LucasNumbersTest do

assert LucasNumbers.generate(25) == sequence
end

@tag task_id: 3
test "catch incorrect non-integer arguments" do
assert_raise ArgumentError, "count must be specified as an integer >= 1", fn ->
LucasNumbers.generate("Hello world!")
end
end

@tag task_id: 3
test "catch incorrect integer arguments" do
assert_raise ArgumentError, "count must be specified as an integer >= 1", fn ->
LucasNumbers.generate(-1)
end
end
end
Loading