Today I Learned

Using A Leading Underscore for Private Functions

You may be familiar with using a leading underscore to denote a parameter whose value does not matter for the function.

def some_func(0, _param2), do: 0
def som_func(param1, param2, do: param1 * param2

You can also use a leading underscore on a function name. Per the Elixir docs, you can do this to keep a function from being imported by default.

I learned in the book Programming Elixir you can use it on private functions that have the same name as public functions. Here is an example using FizzBuzz.

defmodule FizzBuzz do
  def fizzbuzz(n) when n > 0, do: Enum.each(1..n, &_fizzbuzz/1)

  defp _fizzbuzz(n) when rem(n, 15) == 0, do: IO.puts("FizzBuzz")
  defp _fizzbuzz(n) when rem(n, 3) == 0, do: IO.puts("Fizz")
  defp _fizzbuzz(n) when rem(n, 5) == 0, do: IO.puts("Buzz")
  defp _fizzbuzz(n), do: IO.puts(n)
end

Another form of this would be to start the function name with do_.

def sum, do: do_sum
defp do_sum do: 1 + 1

I find using do_ is easier to read than using _. It also avoids potential confusion with the other use of _. Better yet, use a different function name. In the above example, use fizzword instead of _fizzbuzz.

Tail Call Optimization For Recursive Functions

By using a tail call optimization, you can greatly decrease the memory usage of a recursive function. However, this can come at a cost of code complexity. It is probably best to avoid it unless your function will be going through a high amount of iterations or unless you can implement it in an easy understand and maintain way. Standard recursive function that requires lots of memory when passing in a high number for the argument.

defmodule Factorial do
  def of(0), do: 1
  def of(n) when n > 0, do: n * of(n - 1)
end

Tail call optimized function that consumes significantly less memory than the above.

defmodule TRFactorial do
  def of(n), do: factorial_of(n, 1)
  defp factorial_of(0, acc), do: acc
  defp factorial_of(n, acc) when n > 0, do: factorial_of(n - 1, n * acc)
end

Divide And Conquer: Merge Sort Algorithm

This is an example of the merge sort algorithm using Elixir. It splits a list into smaller parts before merging it back together in a sorted list.

defmodule Sort do
  def ascending([]), do: []
  def ascending([a]), do: [a]

  def ascending(list) do
    half_size = div(Enum.count(list), 2)
    {list_a, list_b} = Enum.split(list, half_size)

    merge(
      ascending(list_a),
      ascending(list_b)
    )
  end

  defp merge([], list_b), do: list_b
  defp merge(list_a, []), do: list_a

  defp merge([head_a | tail_a], list_b = [head_b | _]) when head_a <= head_b do
    [head_a | merge(tail_a, list_b)]
  end

  defp merge(list_a = [head_a | _], [head_b | tail_b]) when head_a > head_b do
    [head_b | merge(list_a, tail_b)]
  end
end

Example of Bounded Recursion

“A bounded recursion is a type of recursive function in which the successive calls to itself have an end. It’s the most common type of recursive function, present in all list navigation code. Every time a recursive function calls itself, that’s an iteration; every time a bounded recursion iterates, it requires fewer iterations to finish. We are decreasing the problem in each iteration, even if we can’t easily predict the total number of iterations.” ~Learn Functional Programming with Elixir

defmodule​ Sum ​do​
  ​def​ up_to(0), ​do​: 0
  def​ up_to(n), ​do​: n + up_to(n - 1)
​end
iex>​ c(​"​​sum.ex"​)
​iex>​ Sum.up_to(10)
55

Pattern Match Using The Concatenating Operator <>

While reading Learn Functional Programming with Elixir, I picked up a nice little tidbit for using Elixir’s <> operator with pattern matching. In Elixir, we can use <> to concatenate two strings.

iex> "Hello " <> "World!"
"Hello World!"

Thanks to the power of pattern matching, we can also use it to pattern match the beginning of a string.

iex> "Hello " <> world = "Hello World!"
iex> world
"World!"

However, we cannot use it to pattern match when the variable is on the left side of the <> operator.

iex> hello <> " World!" = "Hello World!"
** (CompileError) a binary field without size is only allowed at the end of a binary pattern and never allowed in binary generators

While we could get fancy and use something like String.reverse to flip our string and pattern match that way, as suggested in the book, we are probably better off just using Regex.

Splitting Panes in tmux on the Current Directory

I have started using tmux with Vim lately to further increase my productivity when coding. After spending some time learning how to use it, tailoring its behavior to my liking, and spending waaayyy too much time customizing the status line, I am feeling pretty good about the decision. Something that has been bugging me is splitting panes and then needing to CD into the correct directory.

Thankfully, this can be resolved by passing the -c "#{pane_current_path}" option. From my .tmux.conf:

# Splitting panes with | and -
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"

# Open new window with current directory
bind-key c new-window -c "#{pane_current_path}"

Now when I create a new window or split a pane, it will use my current pane’s directory. Much better!