English3000

English3000

Using functional design to reduce arity

I was implementing a tail recursive BST using functional design. However, I’m getting stumped in one area. Right now, my insert/3 and insert_or_traverse/4 both use 3 of the same arguments.

I’m trying to figure out how to refactor so that both have access to these arguments but I don’t have to pass all 3 to the helper function.

defmodule BST do
  @type node :: %{value: any, left: node | nil, right: node | nil}
  def node(value \\ nil, left \\ nil, right \\ nil) do
    %{value: value, left: left, right: right}
  end

  def insert(nil, value), do: node(value)
  def insert(%{value: nil} = root, value), do: node(value)
  def insert(root, value), do: insert(root, root, value)

  def insert(root, %{value: node_value} = tree, value) do
    option = if node_value < value, do: :left, else: :right
    insert_or_traverse(root, tree, value, option)
  end

  defp insert_or_traverse(root, tree, value, option) do
    case Map.get(tree, option) do
        nil -> Map.put(tree, option, node(value)); root
      child -> insert(root, child, value)
    end
  end
end

P.S. Doing a bit of research, there’s a body recursive implementation that doesn’t hit this problem.

Marked As Solved

OvermindDL1

OvermindDL1

Eh, that’s F#'s definition, and even then that’s a side site so I don’t think that is right anyway…

Curry: Break apart a function into single-argument functions that return a closure around the rest, thus turning (int, int, int) -> int into int -> int -> int -> int.

Partial Application: Where you supply partial arguments to a function call, thus creating a closure that accepts the rest.

Currying happens at the function definition site.

Partial Application happens at the call site.

Like let’s assume that a _# in an Elixir & call created a new argument in a closure, and you have a function blah/3 that takes 3 arguments, then doing &blah(1, _1, 2) would partially apply the function blah with 2 argument (first and third) and left a ‘hole’ in the second argument, thus effectively making fn a1 -> blah(1, a1, 2) end. Where making blah a curried function would instead mean doing def blah(a), do: fn b -> fn c -> a+b+c end end and would have to be called like blah(1).(2).(3), however note that this lets you in-order partially apply by just doing something like blah(1).(2), but doesn’t let you out-of-order partially apply like the prior example without a proper partial application pattern like the above example has (which most curry’d languages work around by adding functions like swap and so forth).

Also Liked

peerreynders

peerreynders

def insert(root), do: fn value -> insert(root, root, value) end

My current understanding is that partial application is the process of taking a function f of arity n and a list of arguments of length m and producing a new function which has an arity less than n (usually (n-m)).

Your function insert/1 simply returns an anonymous function f/1. Its implementation suggest that you are attempting to emulate the effects of partial application by capturing at least one of the arguments inside a closure for a function to be called at a later point in time.

If you had curried insert/2 you would still end up with a function f/2, i.e. the arity would remain unchanged. However being curried f(1) would return g/1 while f(1,2) would return a result value.

Example: What Ramda curry does for JavaScript (which actually goes even further as the R.__ placeholder allows for the more general partial application of single argument values).

peerreynders

peerreynders

There are a lot of confused explanations for partial application and currying.

I’m going back to why currying was invented in the first place:

Haskell book, p.10:

Each lambda can only bind one parameter and can only accept one argument. Functions that require multiple arguments have multiple, nested heads. When you apply it once and eliminate the first (leftmost) head, the next one is applied and so on. This formulation was originally discovered by Moses Schönfinkel in the 1920s but was later rediscovered and named after Haskell Curry and is commonly called currying.

In partial application you start with a function with multiple parameters and each partial application provides some of the arguments, creating a function with the remaining unapplied parameters.

Example language implementations:
Clojure
JavaScript

The point being - when performing partial application one of the arguments is usually the function that is subject to partial application.

FYI: SRP is misnamed:

Gather together those things that change for the same reason, and separate those things that change for different reasons.

So it’s about “reasons to change” rather than “single responsibility”.

I recommend watching
YOW! 2013 Kevlin Henney - The SOLID Design Principles Deconstructed

Where Next?

Popular in Questions Top

bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
sacepums
Hey guys. I'm new to elixir and im really stocked about it. But I ran into a bit of problem - I need to convert a date sting, for examp...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
LegitStack
I’m trying to make a websocket server in Phoenix or raw Elixir. I heard about gun, I think I could use cowboy, but since I’m not that sma...
New
chewm
Hi guys, nice to meet you to the whole forum, I’m new here, I’m trying to configure visual studio code for elixir, right now the intellis...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New

Other popular topics Top

ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? https://hexdocs.pm/ecto/Ecto.Repo.h...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 42633 214
New
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New

We're in Beta

About us Mission Statement