(Even More) Functional Elixir — 1 If you (like me) got into Elixir from an object-oriented language, then concepts like may not be very familiar. Some of them do not apply by default to Elixir. But they are part of the and worth exploring. currying, function composing and pointfree functions general functional programming (FP) concepts I started with this free book recommended by a colleague: . I would recommend it to anybody getting into functional . It uses and a few libraries to exemplify the concepts. Yet, JS is not my main language, so I’m very curious to see how those apply in Elixir. Professor Frisby’s Mostly Adequate Guide to Functional Programming programming JavaScript Anything those days is about cryptocurrencies. To keep up with the trends let’s build a small crypto price checker. Then we will refactor it using FP concepts. Initial Implementation The public function takes the amount in GBP as only argument. It outputs the number of crypto-coins you can buy with. Example: buy_crypto_with_gbp(2000) =>[BTC: 0.18983617051918897,ETH: 1.9337893873932355,LTC: 10.66955239648603] The role of the module is to communicate with the external APIs and return the exchange rates. You can find the implementation in the . It exposes 2 public functions: Support Github repo # exchange rate between 2 currenciesexchange_rate("USD", "GBP") => 0.7463 # exchange rate between crypto and USDlist_crypto_usd() => [BTC: 14256.67, ETH: 1371.76, LTC: 262.51] There are a few simple actions happening in the code above: get a list of the 3 cryptocurrencies prices in USD get an exchange rate between 2 currencies convert the list of crypto prices from USD to GBP. map the quantity for each crypto-coin The challenge is to refactor the code above using the functional concepts of currying, composing and pointfree. Curry, Compose, Pointfree First of all, I must say that those concepts are not provided with Elixir out of the box. We could implement some of them on our own, but it’s safer and easier to make use of this amazing package: . You may say that we can already compose functions in Elixir with the pipe operator. Stay with me, the composing we are going to use is slightly different. Add the Quark package in the mix file, and at the top of the module. Quark |> use Quark Currying Is the ability to call a function that takes many arguments, with one argument at a time. Each time it will return a new function until the last argument is applied and the result is returned. Quark defines currying with or for private functions. defcurry defcurryp Let’s start by determining the exchange rage from USD to GBP. Add a wrapper around our function: Support.exchange_rate/2 defcurry exchange_rate(from, to) doSupport.exchange_rate(from, to)end Now you can start to apply the arguments one by one to our new function. You can assign the partial result (which is a function) to a variable. Or it can become a new function definition: # apply argumentsexchange_rate.("USD").("GBP") => 0.7463 # assign resulting function to a variablefrom_usd = exchange_rate.("USD") => #Function<5.65603100/1 in CryptoCurry.exchange_rate/0> from_usd.("GBP") => 0.7463 # new function definitiondef exchange_rate_from_usd doexchange_rate().("USD")end exchange_rate_from_usd.("GBP") => 0.7463 Next step is to apply the conversion above to the cryptocurrencies info we receive . We use the same function defined in the Initial implementation, but we just currying it: {BTC: 14256.67} apply_conversion/2 defcurry apply_conversion(rate, {crypto, value_usd}) do{crypto, value_usd * rate}end If we follow the same logic as above we can now do the following to the bitcoin value in GBP: apply_conversion_gbp =apply_conversion.(exchange_rate_from_usd.("GBP")) => #Function<7.34465968/1 in CryptoCurry.apply_conversion/0> apply_conversion_gbp.({:BTC, 14265.67}) =>{:BTC, 10646.469520999999} Getting a bit confusing? This is where the next concept may come handy. Composing The Elixir pipe operator takes the output from the expression on its left side and passes it as the first argument to the function call on its right side. |> The composing is very similar, only it passes a function as the argument to another function. It can be: right to left — the mathematical way — represented with <|> left to right — the flow way, as the Elixir pipe — represented with <~> Let’s look at a small example outside our test application: In this case: bazz_rl.("a").("b") == bazz_lr.("a").("b") Back to the crypto example, we are going to keep close to the FP book and use the mathematical way of composing. We want to define a function that will take the crypto data and convert it to GBP. def apply_conversion_gbp do(apply_conversion() <|> exchange_rate_from_usd()).("GBP")end will partially apply as its first argument. The resulting function will be called with the attribute. The result is, of course, another function that can be called with crypto data: apply_conversion exchange_rate_from_usd "GBP" apply_conversion_gbp.({:BTC, 14265.67}) =>{:BTC, 10646.469520999999} We are almost there. Need a function that will return the quantity of coin that we can buy with the amount of GBP. We already have that function from the Initial implementation. Just need to curry it. defcurryp get_quantity({crypto, value_gbp}, amount) do{crypto, amount / value_gbp}end Mapping and composing If you remember from the Initial example, we were iterating twice over the crypto data list. Once to apply the exchange rate and then to get the quantities: Support.list_crypto_usd()|> Enum.map(&apply_conversion(Support.exchange_rate("USD", "GBP"), &1))|> Enum.map(&get_quantity(&1, amount)) This can be inefficient, but math helps us again here: map(f2) <|> map(f1) == map(f2 <|> f1) So we can compose the 2 functions and map them only once. def convert_gbp_and_get_quantity doget_quantity() <|> apply_conversion_gbp()end defcurry buy_crypto_with_gbp(amount) doEnum.map(Support.list_crypto_usd(),&convert_gbp_and_get_quantity().(&1).(amount))end Our application is now in working state. buy_crypto_with_gbp.(2000) =>[BTC: 0.19774571082071027,ETH: 2.0169243958209693,LTC: 11.090413196189877] Pointfree This last step is a cosmetic change in our case. It was the only reason we curried the . buy_crypto_with_gbp/1 Pointfree is the ability to declare the function without mentioning the arguments. We use the Quark package to define a pointfree interface function for our application. defx defx buy_crypto_with_gbp dobuy_crypto_with_gbp().()end Which we can then call with buy_crypto_with_gbp(2000). Putting it all together Quite a long journey, but we’ve made it. Implementing crypto converter using FP concepts. Back to Elixir Yet, keeping some of the learnings from the implementation above, we can refactor our Elixir code, without curry or need for additional libraries. Conclusion If I would need to choose between and implementations above, I would go for the last one. I find the Elixir native way more clear and explicit. CryptoCurry CryptoElixir Currying and composing functions can DRY your code. Can help building specialised functions generic ones. Also, the code may look cleaner as function names are shorter, without so many arguments. But on longer term, or for new people in the project, it can be confusing. Let’s take our example. I see that is called with 2 successive arguments. But I cannot be sure if that is just a partial application or not. I don’t know if it returns a final result or another function waiting for more arguments. convert_gbp_and_get_quantity In the end, it is important to know that we have the option to use those concepts in Elixir as well. Especially if you have a functional background, you may miss them sometimes. I hope the post gave you at least some basic idea about curry, composing and freepoint in Elixir. I would be very curious to find your opinions on Elixir and those FP concepts. If you worked with them in other languages, do you need them in Elixir? If you didn’t, would you consider using them?