Also, Haskell isn't really ML-syntax. I love MLs but find Haskell syntax pretty ugly.
Also, Haskell isn't really ML-syntax. I love MLs but find Haskell syntax pretty ugly.
I've said this before but if you remove all punctuation and capitalisation from English it will make it look "cleaner", but it will also make it awful to read.
Look how "clean" text is if you get rid of all the spaces!
https://en.wikipedia.org/wiki/Scriptio_continua#/media/File%...
Clearly brilliant.
Let's look at three implementations of a doubling function in modern languages where at least two of them are considered "clean" syntaxes.
F#:
let double x =
2 * x
Python: def double(x: int) -> int:
return 2 * x
Rust: fn double(x: i32) -> i32 {
return 2 * x;
}
Tying back to my original point, are the brackets, annotations, semicolons, and return really needed? From my perspective, the answer is no. These are the simplest functions you can have as well. The differences get multiplied over a large codebase.Are people here really making the argument that F# and MLs don't have clean syntax? All three of these functions have the same IDE behavior in terms of types being showcased in the IDE and also in the type-checking processes, with F# and Rust's type-checking happening at the compiler level and Python's happening with MyPy. People might argue that I left off type annotations for F#, and that's true, but I did so because they aren't required for F# to compile and have the same IDE features like the other languages. Even if I did, it would look like:
F# with type annotations:
let double (x: int) : int =
2 * x
which is still cleaner. fn double(x: i32) -> i32 {
2 * x
}
The reason Rust requires types here is because global inference is computationally expensive and causes spooky action at a distance. The only real difference between your F# and this is the braces, which I do personally think makes code easier to read.Of course there’s more overhead in smaller functions. I’d never write this code in Rust. I’d either inline it, or use a closure, which does allow for inference, and dropping the braces given that this is a one liner:
|x| 2 * x
Different needs for different things. # Rust
let double = |x| 2 * x;
double(3);
// F#
let double = (*) 2
double 3
-- Haskell
let double = (*2)
double 3
# Python
double = lambda x: 2 * x
double(3)This also works:
let zeroCount = numbers |> Seq.filter ((=) 0) |> Seq.lengthThe answer is no for this trivial function. As your code goes beyond this it gets harder for humans to parse and so the syntax becomes more necessary.
My earlier analogy is pretty perfect here actually. Do you really need spaces in "thank you"? No clearly not. Does that mean you shouldn't use spaces at all?
> Are people here really making the argument that F# and MLs don't have clean syntax?
No. You are literally replying to a comment where I agreed that it is "clean".
I find Python to be quite readable as well.
That might be true for academics. But most engineers don't consider ML syntax to be the cleanest, since most don't know any ML language.
What syntaxes do engineers find clean? I don't understand the distinction you're making.
* Python, Ruby, C#, Java, Go-style languages?
I imagine most developers operate in neither ML languages nor Lisp-style languages.The most advanced "FP" trick that I imagine most developers use is Fluent-style programming with a whole bunch of their language's equivalent of:
variable
.map do ... end
.map do ... end
.flatten
Addendum: or maybe Linq in C#
Addendum 2:And even the fluent-style trick in those languages tends to follow a similar pattern. Using Kotlin and Ruby as examples, since those are my (edit: main) languages,
variable
.map do |i| something_with(i) end
.map { |i| something_else(i) }
.flatten
shows familiar tricks. The dot operator implies that the thing previous to it has an action being done; and curly braces or the "do" operation both imply a block of some sort, and so a quick glance is easy to follow.In Kotlin, this gets a little bit more confusing (yes, really) because it's common to see:
variable
.map { somethingWith(it) }
.map { somethingElse(it) }
.flatten()
And now there's this magic "it" variable, but that's easy enough to guess from, especially with syntax highlighting.Anything more advanced than that and the cognitive load for these language starts to rise for people that aren't deep in them.
When you're starting working with a new language, that does increase difficulty and may even be so much of a barrier that developers may not want to hop over.
Having familiar constructs not only make it easier to code-switch between languages (people that work on multi-language projects know that pain pretty well), but also decreases the barrier to entry to the language in the first place.
This is like saying "most uncontacted Amazonian tribes don't like Shakespeare, because they've never read it". Sure, but why would we care about their opinion on this topic?
https://law.ubalt.edu/downloads/law_downloads/IRC_Shakespear...
The same idea is probably true with programmers who have grown used to C-like syntax or even Python-like or Ruby-like syntax. Syntax is at least in great part a cultural thing and your "cultural background" can affect your judgement in many cases:
1. Are braces good? Some programmers find them noisy and distracting and prefer end keywords or significant whitespace, but other programmers like the regularity and simplicity of marking all code blocks with braces.
2. Should the syntax strive for terseness or verbosity? Or perhaps try to keep a middle ground? At one end of the spectrum, Java is extremely verbose, but a lot of Java engineers (who have generally been exposed to at least one less-verbose language) are perfectly OK with it. The trick is that the main way that code gets typed in Java used to be copy-paste or IDE code generation (and nowadays with LLMs typing verbose code is even easier) and reading and navigating the code is done with the help of an IDE, so a lot of the effects of having a verbose language are mitigated. Diffs are harder to review, but in the Enterprise app world, which is Java's bread and butter, code reviews are more of a rubber stamp (if they are done at all).
3. Lisp-like S-expression syntax is also highly controversial. Many people who are introduced with it hate it with passion, mostly because the most important syntax feature (the parentheses) is repeated so often that it can be hard to read, but advocates extol the amazing expressive power, where the same syntax can be use to express code and data and "a DSL" is basically just normal code.