Russian Peasant Multiplication — with Elixir — Part 1
In this article series we are going to learn about lots of cool tech.
Higher order functions, Monad and Recursion.
Read more about this method of Multiplication from here:
https://en.wikipedia.org/wiki/Ancient_Egyptian_multiplication#Russian_peasant_multiplication
If you read the about method from WiKi, you will see that we need 2 different calculations. Decrement, Increment, Filtering, Sum.
We will try to be good developers and write tests. I stick with both doc test and unit testing as it fits. I am not going to write all of the possible tests though. Property testing would be the best fit here however it would be out of the scope of this article series.
Also we will be using Monad to introduce a unified data structure and manage side effects better.
In progress project: https://github.com/houmanka/russian_peseant_multiplication
Expectation at the end of the series
iex> RussianPeasantMultiplication.multiply(13, 238)
3094
Add the following to your mix.exs
{:monadex, "~> 1.1.3"}
Doc for Monadex: https://hexdocs.pm/monadex/api-reference.html
Decrement
First we need to reduce our left number to be 1 or 0
# russian_peasant_multiplication_decreament_test.exs
defmodule RussianPeasantMultiplication.DecreamentTest do
use ExUnit.Case
doctest RussianPeasantMultiplication.Decreamentend
Now we have a test lets write the decrement.
mix test test/russian_peasant_multiplication_decrement_test.exs
It should pass.
Here how we did it:
on line 3 we import Monad.Result
where we can use %Monad.Result{error: nil, type: :ok, value: nil}
Line 32 is not needed, you can pass [a_number]
directly into success()
like this
[a_number]
|> success()
|> ...
As we build our application you will see better pattern to do these kind of things.
Line 33, we want to keep our pipeline properly laid out other version would be
state = success([a_number])
decrement(a_number, state) # EWWWW Hell No...
Nope, not going to happen. Too ugly for our code and my eyes have to follow the line to see what is what.
Also Line 33 is using Closure. If you see, we are only accepting 1 argument and the a_number
arg is coming from outside of our closure.
Line 43. we are using unwrap!
to simply crack open the %Monad.Result{}
struct.
Line 44. Kernel.trunc
is just so I can get rid of decimal points, since I don’t need them.
Line 45. I can follow the same way as creating nice pipeline. I left the pipeline out to show you how ugly it can be. We will fix them all later.
(our technical debt here for now)
That is it for now…
Tune in for part 2. (I have written the code, just need to finish up the article :)