elixir-lang/elixir

`mix format` makes Horner form mathematical expressions harder to read

Closed this issue · 4 comments

When formatting polynomial expressions written in Horner form, mix format applies excessive indentation that makes the code harder to read.

Example (a function calculating mean sidereal time):

defmodule SiderealTime do
  def mean(t) do
    100.460_618_37 +
      t * (36_000.770_053_608 +
      t * (0.000_387_933 +
      t * (-1 / 38_710_000)))
  end
end

After mix format:

defmodule SiderealTime do
  def mean(t) do
    100.460_618_37 +
      t *
        (36_000.770_053_608 +
           t *
             (0.000_387_933 +
                t * (-1 / 38_710_000)))
  end
end

Yes, unfortunately, right-leaning expressions like this these the formatter may do a less than ideal job, since those operators are left associative. And unfortunately it is not possible to address this and not make other cases worse. You have a few options:

  1. Disable the formatter for this file
  2. Remove the line breaks you explicitly introduced and let the formatter deal with it all. It should lead to fewer breaks, as the formatter is not trying to keep your breaks and deal with its own
  3. Break the expression on multiple variables giving it distinct names
  4. Convert it to a left leaning expression by swapping the operands for the addition, like below. If you do so, it should introduce less nesting when breaking lines
  defmodule SiderealTime do
    def mean(t) do
      t * (t * (t * (-1 / 38_710_000) + 0.000_387_933) + 36_000.770_053_608) + 100.460_618_37
    end
  end

Thank you so much, José, for taking the time to explain everything to me so clearly.

I'm working on astronomical formulas, which often involve long polynomials. That's why I often need to split long mathematical expressions across multiple lines.

In the end, I've decided to go with a simple and straightforward implementation:

defmodule SiderealTime do
  def mean(t) do
    100.460_618_37 +
      t ** 1 * 36_000.770_053_608 +
      t ** 2 * 0.000_387_933 -
      t ** 3 / 38_710_000
  end
end

Thank you for this wonderful language that is Elixir.

@sunseb128 i have some Astro stuff at https://github.com/kipcole9/astro in case it’s useful to you.

@kipcole9 Nice codebase! It will be very helpful, thank you. I see that you used an abstraction Math.poly/2.