Gleam: Difference of Squares
Problem on Exercism and on Project Euler
pub fn square_of_sum(n: Int) -> Int {}
pub fn sum_of_squares(n: Int) -> Int {}
pub fn difference(n: Int) -> Int {
square_of_sum(n) - sum_of_squares(n)
}
First Iteration: Recursion
Since the square of the sum first takes the sum, my first notion was to use recursion to loop through the range. of numbers being summed.
pub fn square_of_sum(n: Int) -> Int {
let s = sum(n)
s * s
}
fn sum(n: Int) -> Int {
case n {
1 -> 1
_ -> n + sum(n - 1)
}
}
The public function is a wrapper that simply takes the result of the recursive function and squares it. Since Gleam has implicit returns, just multiplying the value by itself being the last statement is the result.
In the recursive function, there is the base case and the recursive case. The base case, which would usually be 0, but adding 0 to any value results in that value, thus it's 1. If n equals 1, return 1, thereby stopping the call chain. For the recursive case, which is for any positive integer greater than 1, add the current number to the result of recursing n - 1.
I used recursion for the sum_of_squares
as well, but I didn't need a wrapper function in this case.
pub fn sum_of_squares(n: Int) -> Int {
case n {
1 -> 1
_ -> n * n + sum_of_squares(n - 1)
}
}
I didn't need the wrapper in this case because given the last function, we saw that the sum of values was the recursive action, while squaring a value is a single action. Summing the squares is thus a recursive action that performs the action of squaring in each frame. When the recursive action was internal, there needed to be a function that takes the result and uses it.
Second Iteration: List stdlib
Looking at others' solutions, I saw that I could use lists instead. So rather than recursion, I used built-in functions for implementing changes.
pub fn square_of_sum(n: Int) -> Int {
list.range(1, n)
|> list.reduce(fn(acc, x) { acc + x })
|> result.unwrap(0)
|> fn(x) { x * x }
}
Here, a list is created of values from 1 to n. That list is then reduced by adding all the elements, but the reduce function of the list std library returns a result, which will either be Error(Nil)
or Ok(<sum>)
, so the result has to be extracted and then I have the result piped to a function that squares the passed value.
I did the same for sum_of_squares
.
pub fn sum_of_squares(n: Int) -> Int {
list.range(1, n)
|> list.reduce(fn(acc, x) { acc + {x * x} })
|> result.unwrap(0)
}
Third Iteration: Iterator stdlib
Reading a little more about Gleam, I found a more direct solution using an iterator.
pub fn square_of_sum(n: Int) -> Int {
iterator.range(1, n)
|> iterator.fold(0, fn(acc, x) { acc + x })
|> fn(x) { x * x }
}
The reason I don't use a built-in function like int.power
is because it returns a result, either Ok
or Error
, which I would then need to unwrap before using. However, an alternative could be:
pub fn square_of_sum(n: Int) -> Int {
list.range(1, n)
|> int.sum
|> fn(x) { x * x }
}
The iterator std library has both reduce and fold. I chose to use fold because reduce returns a result. In this case, the numbers are generated in the function, not provided, so it's guaranteed that the int.sum
and iterator.fold
would iterate on a list of numbers.
Subscribe to my newsletter
Read articles from Stella Marie directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by