Thanks for your detailed reply! As a reminder, my whole purpose in this thread is to try to understand your comment that Haskell is

> impractical to be used as a general-purpose language (because I don't think it's intended as a general-purpose language)

From my point of view Haskell is a general purpose language, and an excellent one (and in fact, the best one!). I'm not actually sure whether you're saying that

1. Haskell is a general purpose language, but it's impractical

2. Haskell is a general purpose language, but it's too impractical to be used as one (for some (large?) subset of programmers)

2. Haskell is not a general purpose language because it's too impractical

(I agree with 1, with the caveat I don't think it's significantly less practical than other general purpose languages, including Python. It's just impractical in different ways!)

That out of the way, I'll address your points.

> can you explain what withJump does? Like, not the intention of it, but what it actually does? This is a rhetorical question--I know what it does--but if you work through the exercise of explaining it as if to a beginner, I think you'll quickly see that this is isn't trivial.

Yes, I can explain what it does! `jumpTo break` throws an exception which returns execution to `withJump`, and the program continues from there. Do you think explaining this to a beginner is more difficult than explaining that `break` exits the loop and the program continues from there?

> It's certainly unintuitive, but I can't think of a case this has ever caused a problem for me in real code.

I can! And not just me. It's caused a lot of problems for a lot of users over the years: https://stackoverflow.com/questions/54288926/python-loops-an...

> Again, is this actually a problem? Any high school kid learning Python can figure out how to set a flag to exit a loop. It's not elegant or pretty, but does it actually cause any complexity? Is it actually hard to understand?

Yes, I would say that setting flags to exit loops causes additional complexity and difficulty in understanding.

> And lots of languages now have labeled breaks.

I'm finding this hard to reconcile with your comment above. Why do they have labelled breaks if it's good enough to set flags to exit loops?

> Arguably the Lua solution (gotos) is the cleaner solution here, but that's not popular. :)

Sure, if you like, but remember that my purpose is not to argue that Haskell is the best general purpose language (even though I think it is) only that it is a general purpose language. It has at least the general purpose features of other general purpose languages. That seems good enough for me.

> What does this even mean? In concrete terms, why do you think I can't see what effects are possible in Python, and what problems does that cause?

def foo(x):
bar(x + 1)

Does foo print anything to the terminal, wipe the database or launch the missiles? I don't know. I can't see what possible effects bar has.

foo1 :: e :> es => IOE e -> Int -> Eff es ()
foo1 ioe x = do
bar1 ioe x

foo2 :: e :> es => IOE e -> Int -> Eff es ()
foo2 ioe x = do
bar2 (x + 1)

I know that foo2 does not print anything to the terminal, wipe the database or launch the missiles! It doesn't give bar access to any effect handles, so it can't. foo1 might though! It does pass an I/O effect handle to bar1, so in principle it might do anything!

But again, although I think this makes Haskell a better language, that's just my personal opinion. I don't expect anyone else to agree, necessarily. But if someone else says Haskell is not general purpose I would like them to explain how it can not be, even though it has all these useful features.

> In all three of the cases that you mention, I can see a sort of aesthetic beauty to the Haskell solution, which I appreciate. But my clients don't look at my code, they look at the results of running my code.

Me too, and the results they see are better than if I wrote code in another language, because Haskell is the language that allows me to most clearly see what results will be produced by my code.

> The fact that you need a blog post to tell people how to resolve an issue exemplifies my point that this is not resolved. Nobody needs to be told how to turn off laziness in Python, because it's not turned on.

Hmm, do you use that line of reasoning for everything? For example, if there were a blogpost about namedtuple in Python[1] would you say "the fact that you need a blog post to tell people how to use namedtuple exemplifies that it is not a solved problem"? I really can't understand why explaining how to do something exemplifies that that thing is not solved. To my mind it's the exact opposite!

Indeed in Python laziness is not turned on, so instead if you want to be lazy you need blog posts to tell people how to turn it on! For example [2].

> The fact is, Haskell does the wrong thing by default here

I agree. My personal take is that data should be by default strict and functions should be by default lazy. I think that would have the best ergonomic properties. But there is no such language. Does that mean that every language is not general purpose?

> even if you write your code to evaluate eagerly, you're going to end up interfacing with libraries where someone didn't do that.

Ah, but that's the beauty of the solution. It doesn't matter whether others wrote "lazy code". If you define your data types correctly then your data types are free of space leaks. It doesn't matter what anyone else writes. Of course, other libraries may use laziness internally in a bad way. I've fixed my fair share of such issues, such as [3]. But other libraries can always be written in a bad way. In Python a badly written library may cause an exception and bring down your worker thread when you weren't expecting it, for example. That's a weakness of Python, but it doesn't mean it's not a general purpose language!

> Laziness still gets advertised up front as being one of the awesome things about Haskell

Hmm, maybe. "Pure and functional" is the main thing that people emphasizes as awesome. You yourself earlier brought up SPJ saying that the next Haskell will be strict, so we both know that Haskellers know that laziness is a double edged sword. I'm trying to point out that even though one edge of the sword of laziness points back at you it's not actually too hard to manage and having to manage it doesn't make Haskell not a general purpose language.

> and while experience Haskell developers are usually disillusioned with laziness, many Haskell developers well into the intermediate level still write lazy code because they were told early on that it's great, and haven't yet experienced enough pain with it to see the problems.

Hmm, maybe. I don't think people deliberately write lazy (or strict) code. They just write code. The code will typically happen to have a lot of laziness, because Haskell is lazy by default. I think that we agree that that laziness is not the best default, but we disagree about how difficult it is to work around that issue.

I would be interested to hear whether you have more specific ideas you can share about why Haskell is not a general purpose language, in light of my responses.

[1] https://blog.teclado.com/pythons-namedtuples/

[2] https://www.tothenew.com/blog/exploring-pythons-itertools-mo...

[3] https://github.com/mrkkrp/megaparsec/issues/486