In real life, I find that Haskell suffers from trying too hard to use the most general concept that‘s applicable (no pun intended). Haskell programs happily use “Either Err Val” and “Left x” where other languages would use the more expressive but less general “Result Err Val” and “Error x”. Also, I don’t want to mentally parse nested liftM2s or learn the 5th effect system ;-)
Whoever wrote that is wrong.
You are the one who is wrong, I'm afraid.
Rust's most important feature! The bootstrapped implementation.
Additionally, unlike some languages that are formally specified before turning to implementation, Rust has subscribed to design-by-implementation. The implementation is the language.
I'm not one to hold that one shouldn't form tentative conclusions until one "has all the fact". Also, I'm not one to hold that readers should trust the opinion of an internet comment writer they know nothing about. I could write a long explanation to support my opinion, but I'm probably not going to.
If not, what is the relevance of your comment?
https://github.com/mozilla/rust/tree/ef75860a0a72f79f97216f8...
> Haskell (GHC): typeclasses, type families
Although SML is older (1983), OCaml is younger than Haskell.
In Python, it's very easy to just write out a for-loops to do these things, and you don't necessarily go looking for alternative ways to do these things unless you know the functional equivalents already. But in Haskell you're forced to do things this way since there is no for-loop available. But after learning that way of thinking, the result is then more compact code with arguably less risk of bugs.
map(function, iterable)
That seems very logical to me, but then, I’m not a functional programmer, I just like map. It’s elegant, compact, and isn’t hard to understand. Not that list comps are hard to understand either, but they can sometimes get overly verbose.filter has also lost ground in favor of list comps, partially because Guido hates FP [0], and probably due to that, there has been a lot of effort towards optimizing list comps over the years, and they’re now generally faster than filter (or map, sometimes).
[0]: https://www.artima.com/weblogs/viewpost.jsp?thread=98196
map(func4, map(func3, map(func2, map(func1, iter))))
vs iter.map(f1).map(f2).map(f3).map(f4)
I made up the syntax for the last one, but most functional languages have a nice syntax for it. Here's F#: iter |> f1 |> f2 |> f3 |> f4
Or plain shell: command | f1 | f2 | f3 | f4Use generator syntax, which is really the more pythonic way to it.
>>> iter = [1,2,3,4]
>>> f1 = lambda x: x*2
>>> f2 = lambda x: x+4
>>> f3 = lambda x: x*1.25
>>> [f3(f2(f1(x))) for x in iter]
[7.5, 10.0, 12.5, 15.0]Second, that's all good and well if all you want to do is map. But what if you need combinations of map and filter as well? You're suddenly dealing with nested comprehensions, which few people like.
In F#, it'll still be:
iter |> f1 |> f2 |> f3 |> f4
Here's an example from real code I wrote: graph
|> Map.filter isSubSetFunc
|> Map.filter doesNotContainFunc
|> Map.values
|> Set.ofSeq
This would not be fun to write in List Comprehensions, but you could manage (only two list comprehensions). Now here's other code: graph
|> removeTerminalExerciseNodes
|> Map.filter isEmpty
|> Map.keys
|> Seq.map LookUpFunc
|> Seq.map RemoveTrivialNodes
|> Seq.sortBy GetLength
|> Seq.rev
|> Seq.toList
BTW, some of the named functions above are defined with their own chain of maps and filters. iter = [1,2,3,4]
f1 = lambda x: x*2
f2 = lambda x: x+4
f3 = lambda x: x*1.25
result = iter
for f in [f1, f2, f3]:
result = [f(v) for v in result]
Then the list comprehension can be moved up to mimic more closely what you're doing with F#, allowing for operations other than "map": result = iter
for f in [
lambda a: [f1(v) for v in a],
lambda a: [f2(v) for v in a],
lambda a: [f3(v) for v in a],
]:
result = f(result)
And a step further if you don't like the "result" reassignment: from functools import reduce
result = reduce(lambda step, f: f(step), [
lambda a: [f1(v) for v in a],
lambda a: [f2(v) for v in a],
lambda a: [f3(v) for v in a],
], iter)In my F# file of 300 lines[1], I do this chaining over 20 times in various functions. Would you really want to write the Python code your way every time, or wouldn't you prefer a simpler syntax? People generally don't do it your way often because it has a higher mental burden than it does with the simple syntax in F# and other languages. I don't do it 20 times because of an obsession, but because it's natural.
[1] Line count is seriously inflated due to my habit of chaining across multiple lines as in my example above.
For example: https://ryi.medium.com/flexible-piping-in-python-with-pipey-...
And another mentioned there: https://pypi.org/project/pipe/
> It's certainly not as clean as F# but neither is it as bad as the original example if there's a lot of functions
items = [1,2,3,4]
gen1 = (x*2 for x in items)
gen2 = (x+4 for x in gen1)
gen3 = (x*1.25 for x in gen2)
result = list(gen3)
It's nicer in a way, certainly closer to the pipe syntax the commenter your replying to is looking for, but kind of janky to have to name all the intermediate steps.This is still backwards?
filter(lambda x: x<5, map(lambda x: 2*x, [1,2,3,4,5]))
filter (<5) . map (*2) $ [1,2,3,4,5]
(Technically the Python version should be cast to a list to have identical behavior.)Same with comprehensions (although nesting comprehensions will always get weird).
[x for x in [2*x for x in [1,2,3,4,5]] if x<5]
[x | x <- [2*x | x <- [1,2,3,4,5]], x<5]Laziness is mostly an anti-pattern.