github / keybase / email
index

Cursed Elixir

Let's write some Elixir.

defmodule FooBar do
  def foo(a) do
    if a < 0 do
      bar(a, -1)
    else
      bar(a, 1)
    end
  end

  defp bar(a, b) do
    IO.inspect(a * b)
  end
end

Not very useful, but that's good enough for our purpose.

I like Elixir, but I think most of the time it just looks like functional Ruby. I want to make this code look like Elixir.

First, this code is lacking every Elixir developer's best friend: |>. Let's add some |>s.

defmodule FooBar do
  def foo(a) do
    if a < 0 do
      a |> bar(-1)
    else
      a |> bar(1)
    end
  end

  defp bar(a, b) do
    (a * b) |> IO.inspect()
  end
end

Meh. It's definitely better, but I mean, that's only 3 |>s. I want more |>s.

We have an if in there, so maybe we can do something with it?

defmodule FooBar do
  def foo(a) do
    (a < 0) |> if do
      a |> bar(-1)
    else
      a |> bar(1)
    end
  end

  defp bar(a, b) do
    (a * b) |> IO.inspect()
  end
end

We sure can! That's one more |>. Can we do better than this?

Well... > and * are Kernel functions, so maybe...

defmodule FooBar do
  def foo(a) do
    a |> Kernel.<(0) |> if do
      a |> bar(-1)
    else
      a |> bar(1)
    end
  end

  defp bar(a, b) do
    a |> Kernel.*(b) |> IO.inspect()
  end
end

This is great, can we keep going?

The Elixir docs say defmodule is just a macro. Does that mean I can just |> into defmodule?

FooBar |> defmodule do
  def foo(a) do
    a |> Kernel.<(0) |> if do
      a |> bar(-1)
    else
      a |> bar(1)
    end
  end

  defp bar(a, b) do
    a |> Kernel.*(b) |> IO.inspect()
  end
end

Yes you can!

def and defp are macros too right?

FooBar |> defmodule do
  a |> foo() |> def do
    a |> Kernel.<(0) |> if do
      a |> bar(-1)
    else
      a |> bar(1)
    end
  end

  a |> bar(b) |> defp do
    a |> Kernel.*(b) |> IO.inspect()
  end
end

So many pipes! 😍

We're getting somewhere, but something still doesn't feel right. This module really isn't doing much, so maybe it should not be that long? Also, I think we need more :. Atoms are very Elixir-y, so let's do more of that:

FooBar |> defmodule(do: (
  a |> foo() |> def(do: a |> Kernel.<(0) |> if(do: a |> bar(-1), else: a |> bar(1)))

  a |> bar(b) |> defp(do: a |> Kernel.*(b) |> IO.inspect())
))

We're :doing great!

You know what's also very Elixir-y? Lists. Lists and tuples.

FooBar |> defmodule([{:do, (
  a
  |> foo()
  |> def([{:do, a |> Kernel.<(0) |> if([{:do, a |> bar(-1)}, {:else, a |> bar(1)}])}])

  a |> bar(b) |> defp([{:do, a |> Kernel.*(b) |> IO.inspect()}])
)}])

Who's going to say this looks like Ruby now? ⚗️


discussion on hackernews / discussion on reddit