
Hi Paul, Thus quoth PY on Mon Jul 16 2018 at 09:44 (+0200):
So, motivation of monads introduction (for me, sure, I'm very subjective) is to workaround Haskell model,
Sometimes (e.g., when you want to be able to prove correctness) you actually want to express everything in a small basis of concepts/operations/tools. To me, monads are cool precisely because they allow _explicit_ sequencing of actions in a non-sequential model. By the way, the lift function you mentioned in a previous E-mail does have a value for the programmer: it shows at which level of the monad transformer stack the action takes place (for example). Thus quoth PY on Mon Jul 16 2018 at 09:44 (+0200):
1. State monad allows you to mark change of THIS state, so you can easy find where THIS state is changing (tracking changes) 2. Singleton with FSM allows you to *control* change and to isolate all change logic in one place
1st allows spaghetti, 2nd - does not. 2nd force you to another model:
You seem to like it when your paradigm forces you to do something (just like I do). Now, monads force you to program in a certain way. Furthermore, you may say that FSM are a workaround of the way in which conventional operative languages manipulate state. My point is: whether monads are a workaround or a solution depends on the angle at which you look at the situation. (I think you say something similar too.) - Sergiu Thus quoth PY on Mon Jul 16 2018 at 09:44 (+0200):
So I think if you don't see anybody explicitly mentioning spaghetti issues with State that's for some people it's just hiding in plain sight and they either aren't consciously aware of it, or find that area so self-explaining that they do not think they really need to explain that.
IMHO State monad solution is orthogonal to my point. It does not force you to isolate state change in one place with explicit control, it only marks place where it happens. This info is needed to compiler, not to me. For me - no benefits. Benefit to me - to isolate changing, but with State I can (and all of us do it!) smear change points throughout the code. So, my question is: what exact problem does solve State monad? Which problem? Mine or compiler? Haskell pure lambda-only-abstraction limitation? OK, if we imagine another Haskell, similar to F#, will I need State monad yet? IMHO - no. My point is: State monad is super, in Haskell, and absolutely waste in other languages. I will isolate mutability in another manner: more safe, robust and controllable. Recap: 1. State monad allows you to mark change of THIS state, so you can easy find where THIS state is changing (tracking changes) 2. Singleton with FSM allows you to *control* change and to isolate all change logic in one place
1st allows spaghetti, 2nd - does not. 2nd force you to another model: not changes, but change requests, which can return: "not possible". With Haskell way the check "possible/not possible" will happen in locations where you change state in State monad: anywhere. So, my initial point is: State monad is about Haskell abstraction problems, not about developer problems.
Sorry, but that's not what OO is about. Also, I do not think that you're using general FSMs, else you'd be having transition spaghetti. To be precise, then yes, you are right. But such model forces me more, then monadic model. When you create singleton "PlayerBehavior", and have all setters/getters in this singleton and already check (in one place!) changes - next step is to switch from checks to explicit FSM - in the same place. Haskell nothing offers for this. You *can* do it, but monads don't force you and they are about Haskell problems, not mine. Motivation of State monad is not to solve problem but to introduce state mutability in Haskell, this is my point. OK, State monad has helpful side-effect: allows to track change of concrete THIS state, but I can do it with my editor, it's more valuable to Haskell itself, then to me, because no problem to mutate state: Haskell allows it, Haskell also does not guard you to mutate this state anywhere in the application.
I'm agree with you 100%. My point is related to accents only, my thesis is: monads have value, but it's small, it's justified in Haskell with its limitation to one abstraction, but I don't need monads in other languages, their value in other languages is super-small (if even exists). So, motivation of monads introduction (for me, sure, I'm very subjective) is to workaround Haskell model, not to make code more safe, I'm absolutely sure: monads nothing to do with safety. It's like to use aspirin with serious medical problem :)
Let me repeat: What you call a "message" is just a standard synchronous function call. The one difference is that the caller allows the target type to influence what function gets actually called, and while that's powerful it's quite far from what people assume if you throw that "message" terminology around. I mentioned Erlang early: the same - you send message to FSM which will be lightweight process. Idea of agents and messages is the same in Smalltalk, in QNX, in Erlang, etc, etc... So, "message" does not always mean "synchronous call". For example, QNX "optimizes" local messages, so they are more lightweight in comparison with remotely messages (which are naturally asynchronous). But "message" abstraction is the same and is more high-level then synchronous/asynchronous dichotomy. It allows you to isolate logic - this is the point. Haskell nothing to do with it: you smear logic anywhere. But now you mark it explicitly. And you have illusion that your code is more safe.
But that's not the point. The point is that Haskell makes it easy to write non-spaghetti.
How? In Haskell I propagate data to a lot of functions (as argument or as hidden argument - in some monad), but with singleton+FSM - you can not do it - data is hidden for you, you can only *call logic*, not *access data*. Logic in Haskell is forced to be smeared between a lot of functions. You *CAN* avoid it, but Haskell does not force you.
BTW you have similar claims about FSMs. Ordinarily they are spaghetti incarnate, but you say they work quite beautifully if done right. (I'm staying sceptical because your arguments in that direction didn't make sense to me, but that might be because I'm lacking background information, and filling in these gaps is really too far off-topic to be of interest.)
I respect your position. Everybody has different experience, and this is basically very good!
We often repeat this: “side-effects”, “tracks”, “safe”. But what does it actually mean? Can I have side-effects in Haskell? Yes. Can I mix side-effects? Yes. But in more difficult way than in ML or F#, for example. What is the benefit?
That it is difficult to accidentally introduce side effects. Or, rather, the problems of side effects. Formally, no Haskell program can have a side effect (unless using UnsafeIO or FFI, but that's not what we're talking about here).
Actually if we look to this from high-level, as to "black box" - we see that it's truth. Haskell allows to have them, to mix them but in different manner.
Yes they will. Some tests will fail if they expect specific output. If the program has a text-based user interface, it will become unusable.
And wise-versa: if I will remove "print" from such tests and add "pure" - they can fail too. IMHO purity/impurity in your example is related to expected behavior and it violation, not to point that "more pure - less bugs". Pure function can violate its contract as well as impure.
Yes they will become buggy. You'll get aliasing issues. And these are the nastiest thing to debug because they will hit you if and only if the program is so large that you don't know all the data flows anymore, and your assumptions about what might be an alias start to fall down. Or not you but maybe the new coworker who doesn't yet know all the parts of the program. That's exactly why data flow is being pushed to being explicit.
So, to avoid this I should not mix read/write monads, to avoid RWST. In this case they should be removed from the language. And monad transformers too. My point is: there is some misunderstanding - I often listen "side-effects are related to errors", "we should avoid them", "they leads to errors", etc, etc, but IMHO pure/impure is needed to FP language compiler, not to me. This is the real motto. Adding of side-effects does not lead to bugs automatically. Mostly it does not. More correct is to say: distinguish of pure/impure code is better to analyze the code, to manipulate with it, to transform it (as programmer I can transform F# code *easy because no monads*, in Haskell *compiler* can transform code easy *because monads*). More important argument for me is example with Free monads. They allows to simulate behavior, to check logic without to involve real external actions (side-effects). Yes, OK, this is argument. It's not explicitly related to buggy code, but it's useful. It remember me homoiconic Lisp code where code can be processed as data, as AST.
Actually, I had a big interesting discussion in my company with people which does not like FP (the root why I become to ask such questions to himself). And I got their arguments. I tried to find solid base of mine. But currently I see that I like Haskell solutions itself, and I can not show concrete examples where they are needed in real world, without Haskell specific limitations. I know that those limitations lead to slow compilation, to big and complex compiler, I can not prove that side-effects means "lead to error", or (more interesting) that it's bad to separate side-effects from each other. F#, ML, Lisps have "do-" block and no problem with it. They don't need transformers to mix 2 different effects in one do-block. If you can prove that this decision leads to bugs and Haskell solution does not: it will be bomb :) I think, will be a lot of people in CS which will not agree with you ever.
--- Best regards, Paul
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.