
I actually lost interest, because you are kind of trying to tell me that because of your lack of _familiarity_ with monads, _my_ benefits do not count. I cannot agree with this statement and with this approach. But since there were questions, I'll answer and do some small clarification.
I asked because never tried Eta. So, if you are right, seems no reasons to develop Eta... I am not sure why you are bringing Eta as an example to this discussion just to point later that you have no experience with it. The point of Eta is to run Haskell on JVM. Haskell as of GHC, and not some hypothetical hybrid language (that would be Scala). If you want a decent language, and you must run on JVM then you use Eta. If you don't need to run on JVM - you don't use Eta.
No better definition then original: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/computatio... You see, they are different. Now it is your turn to read this link. The second sentence on that link says: "They can be used to provide a convenient syntax for *monads*, a functional programming feature that can be used to manage data, control, and side effects in functional programs." The emphasis on _monads_ isn't mine, it is original. The computation expressions are _monadic_ (when they obey laws, but that link doesn't say anything about laws, unfortunately).
Something like this: user?.Phone?.Company?.Name??"missing"; ? Still no.
It does not force you to isolate state change in one place with explicit control, it only marks place where it happens.
If I add “print” for debug purpose in some subroutines, will they become buggy? No. Then you add this code inside a transaction and voila - yes, you do have a bug. In fact, my colleague who used to work at Nasdaq, had a story about exactly
processAttack :: (MonadState s m, HasBpsCounters s) => Attack -> m Result No benefits for you, tons of benefits for me: I guarantee that this function can only be called if there is access to some BPS counters. I guarantee that this function, and whatever if uses inside itself, can never touch or even look at anything else in my state. I can guarantee that it doesn't cause any other effects like it doesn't call something which calls something which prints to console or writes to DB. And that if during code evolution/refactoring someone does something like that, then it won't compile. this: Once upon a time there was a beautiful code that lived in a transaction. Then someone accidentally introduced a side effect to one of the functions. This function was called from something within that transaction. The bug was noticed after some time when it has done some damage. In Haskell, you can't do IO in STM, so that wouldn't be possible.
Haskell also does not guard you to mutate this state anywhere in the application. I think my example above proves otherwise: in Haskell, I can granularly control who can update which part of the state, which makes your statement invalid.
monads have value, but it's small ... their value in other languages is super-small Again, a VERY bold statement I have to disagree with, once again. F# workflows are monadic, C# LINQ is precisely modelled by E. Meijer as a list monad. They add great value.
With this, I rest my case, thanks for the discussion.
Regards,
Alexey.
On Mon, Jul 16, 2018 at 5:45 PM PY
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.