Nah, that kind of thing doesn’t matter. I just found that having top-level functions worked really well for me in the past 9 years using languages like Elm. I usually arrange things in sections like this:
-- TOPOLOGICAL SORT
topologicalSort : Dict String (List String) -> List String
topologicalSort graph =
... topologicalSortHelp ...
topologicalSortHelp : String -> Dict String (List String) -> List String
topologicalSortHelp key graph =
... whatever ...
whatever : This -> That -> Whatever
whatever this that =
...
-- SOMETHING ELSE
somethingElse : String -> Whatever
somethingElse blah =
...
I use the big -- COMMENTS to group things visually for quickly scanning through. I wrote about this style a bit in the revised guide actually!
I have personally found that this is when my code is easiest to understand and edit, especially when there were long gaps since I last saw it. The important part is that all necessary variables are clearly labelled, whereas when using let blocks, there can be values that just came from somewhere. So it may be annoying to “have more arguments” but to me that is the whole point. Clearly labelled with a type annotation!
Note: If it turned out that code in let was faster if it was taken out, that’s the kind of thing a compiler can do really easily. I would really discourage thinking about perf tradeoffs like that when writing normal Elm code. The new optimization section of the guide also gets into how that is a dead end in most cases anyway!