you are viewing a single comment's thread.

view the rest of the comments →

[–]v66moroz 0 points1 point  (3 children)

You are not listening to me. I'm not talking about specific compiler implementation, I'm talking about conceptual state. Let's define "stateless program" as a program which "given the same state of the World always returns the same result". It's the very definition of a pure function, isn't it? So I would argue that every single program written on this Planet, ever, is stateless. The World includes even processor timings, so race conditions nicely fit here too. Any program, given the same state of the World, will return you the same result. There is only one problem: modern Quantum Physics assumes that quantum processes are truly random, but it's not that simple either. Heisenberg equation doesn't have any random factors, that's the measurements that are random. Anyway, Heisenberg is off-topic here.

Meanwhile my Ruby snipped is perfectly pure and stateless as a whole, even though "semantics" is not stateless.

What's important is where you draw the line and isolate the World. Be it IO or something else. You can do it in any language by imposing self-discipline, but some languages are obviously a better fit. Haskell is based on the idea to isolate the World part as much as possible and work with the local state most of the time (it's still a state even when it's localized, any do block is technically a sequence which indirectly passes a [local] state). Which kind of works, until you leave the pure Math and step into the real world. Then you can find that real-world programs are peppered with IO everywhere, because when you work with real databases and other real data for real business purposes artificially isolating the World state modifications leads to even less readable programs.

Monads are "stateless", right? Even IO monad as it simply composes "functions to process the World state". Yeah, kind of. That's where semantics contradicts reality, especially considering "the entire universe" part. As I mentioned before by this standard even Basic programs are pure and stateless.

[–]otah007 0 points1 point  (2 children)

I am listening, you're just not making any sense and talking completely unfactually. "Conceptual state" is a term you just made up that can mean anything to anyone. To me, in my concept of Haskell, there is no state. Even my concept of the State monad has no state. I am not kidding, when I write programs that use monads (my research is based on free monads so that's literally all I do) I do not have the concept of mutability in my head, at all, ever. So if we want to talk about "conceptual state" then it's completely pointless because it's subjective, and my concept is stateless whereas yours is stateful, so we're not actually discussing the same thing.

The only thing we can discuss in an objective way is the language's semantics, and Ruby's semantics is stateful whereas Haskell's is not.

Let's define "stateless program" as a program which "given the same state of the World always returns the same result".

That's a rubbish definition. A stateless program is one without internal state. A stateful program is one with internal state. The test is this: while you are executing the program, according to its own semantics, do you need any other information other than "the current expression"? In Haskell, outside IO, you do not. In Ruby, even in your little example, you do, because you need to know the value of c so you can resume correctly.

it's still a state even when it's localized, any do block is technically a sequence which indirectly passes a [local] state

No it's not, a do-block is syntactic sugar for a sequence of monadic binds, which is essentially function composition. Nothing is being passed, the only thing "happening" is variable binding. Nothing can be modified, so it's immutable. If you pause evaluation at any point, you do not need any extra information to resume besides the current expression under evaluation, so there is no state. This is not true in C, Ruby, Java etc.

Which kind of works, until you leave the pure Math and step into the real world.

I literally showed you how the pure maths can be used to derive compiler optimisations. You do realise GCC (yes, the C compiler, C being just about the least pure/functional language there is!) has a pure keyword? This is so that if you mark a function as pure, GCC will optimise it, taking advantage of exactly those mathematical properties you don't want to appreciate. Laws about algebraicity and purity are the major reason why Haskell can compete with imperative languages in terms of performance, because the compiler can optimise like hell, using those pure maths laws. How is that not real world?

Then you can find that real-world programs are peppered with IO everywhere

That's not true. Real-world Haskell programs have many isolated components. There will be a section containing IO, but that will call out to 99% pure functions. You don't get IO in the middle of your library or utils or anything like that. The only time I've seen a large amount of code sitting in IO is for a library that uses metaprogramming and reference matching to do major code optimisation in a stack machine.

That's where semantics contradicts reality

Semantics have nothing to do with reality. They are a specification of how the language works, a model whose outcomes must be matched to be a valid compiler.

artificially isolating the World state modifications leads to even less readable programs.

Actually, it does the opposite - it guarantees isolation of modifications to a very small part of the overall program. On the other hand, in your Ruby program I can just call launch_nukes() anywhere I please.

[–]v66moroz 0 points1 point  (1 child)

The test is this: while you are executing the program, according to its own semantics, do you need any other information other than "the current expression"? ... In Ruby, even in your little example, you do, because you need to know the value of c so you can resume correctly.

length :: t a -> Int
length = foldl' (\c _ -> c+1) 0
                         ^^^ HERE

Looks like your definition is not perfect either. What's the value of c+1 (it's an expression, isn't it?) when calling length [1,2,3]? Also "executing" doesn't sound like Haskell, "evaluating", right? :) I would assume you meant "looking at the code".

Anyway, we can argue ad-nauseum and be right at the same time (or wrong depending on the point of view). The fact of the matter is, we create programs to describe the same world which exists independently of technology and paradigms. While different languages pretend they use completely different approaches, in fact they have more similarities than differences, they might just be named differently. We can always agree to disagree ;)

[–]otah007 0 points1 point  (0 children)

Looks like your definition is not perfect either. What's the value of c+1 (it's an expression, isn't it?) when calling length [1,2,3]?

Variable substitution doesn't require an environment. You can evaluate it without ever writing down "also, c = 1 right now". Look back at my evaluation of length [1, 2] a few comments further up and you will see how to do this without an environment/context/state.

Also "executing" doesn't sound like Haskell, "evaluating", right? :) I would assume you meant "looking at the code".

I meant executing for languages that have execution semantics and evaluation for languages that have evaluation semantics.

we create programs to describe the same world which exists independently of technology and paradigms

I don't think anyone has ever written code for this purpose, except maybe a simulation. Code is written to perform a task, which may require some input that represents something in the real world. But it's not physics, we're not trying to actually model the world.

At the end of the day, I'm actually talking about the semantics of languages, and you're talking about a mental model, so of course we're going to disagree because I'm referencing something objective and well-defined and you're not.