Can ChatGPT help with writing more idiomatic Elixir?

I’m using Advent of Code to learn Elixir. I wrote a solution to Day 1 that worked but looked a bit ugly. I asked ChatGPT to rewrite it more idiomatic Elixir:

Prompt:
can you rewrite this to be more idiomatic Elixir?

  def part_1(input) do
    input
    |> String.split("\n\n")
    |> Enum.map(fn s ->
      s
      |> String.split("\n")
      |> Enum.map(fn t ->
        t
        |> String.trim()
        |> String.to_integer()
      end)
      |> Enum.sum()
    end)
    |> Enum.max()
  end

Here’s how it answered:

Here is a possible way to rewrite the part_1/1 function in a more idiomatic Elixir style:

def part_1(input) do
  input
  |> String.split("\n\n")
  |> Enum.map(fn s ->
    s
    |> String.split("\n")
    |> Enum.map(&String.trim/1)
    |> Enum.map(&String.to_integer/1)
    |> Enum.sum()
  end)
  |> Enum.max()
end

This rewrite uses the & operator to convert the String.trim/1 and String.to_integer/1 functions into anonymous functions, which allows them to be passed directly to the Enum.map/2 function. This is a more concise and idiomatic way to write the code, and it can make it easier to read and understand.

I hope this helps! Let me know if you have any other questions.

Pretty amazing!!

3 Likes

ChatGPT hasn’t discovered credo yet then.

https://hexdocs.pm/credo/Credo.Check.Refactor.MapMap.html

3 Likes

Hello,
You really should take into account that each call to Enum in the final code implies a full walk through the entire list. So this can be ok for small lists but I for myself consider this as bad style.
The Enum module is full of functions that really should be studied in-depth as to find the appropriate one for the desired behavior.
In your case, I would use reduce that does all in one pass: traverse the list, do the proper conversion you need as in your first function and calc the sum in the accumulator, all in one pass.

So I would write it like this:

def part_1(input) do
    input
    |> String.split("\n\n")
    |> Enum.map(fn s ->
      s
      |> String.split("\n")
      |> Enum.reduce(0, fn t, acc ->
        t |> String.trim() |> String.to_integer() |> Kernel.+(acc)
      end)
    end)
    |> Enum.max()
  end

Cheers,
Sébastien.

3 Likes

There is a whole thread of alternative examples to this code :slight_smile:

Yes and that’s good to see the various tries to the challenge.
But my main point was to alert on the stacking of Enum.map calls that is easy with the pipe operator but that comes with an associated cost. The initial post conclude that the AI was pretty amazing, I don’t share this feeling (plus the fact that a recent submission we did at work result in a not so bad looking implementation for the problem we submit to it, but the result was totally false and the AI was bluffing… Maybe it could be good at poker !)

2 Likes