3 ms·
"It appears that in the presence of mutable state, a lot of the advantages of monads become moot." If you have imperative state then toy uses of the state mona
by Chattered 12y ago
"It appears that in the presence of mutable state, a lot of the advantages of monads become moot."
If you have imperative state then toy uses of the state monad might be overkill. But, for example, in a parser, imperative state is unlikely to help you. Here, you want state to be discarded at failure and old states restored by backtracking. The execution paths are highly complicated (as they always are when you are working with what are effectively continuations), and trying to reason about these paths in the face of imperative update isn't easy, and is likely to lead to weird bugs.
Toy examples are not generally going to help you appreciate monads, and I think there's a fourth requirement to make them work in a language: you need a powerful type-system. I'd say that monads haven't taken F# by storm because F# isn't powerful enough to type-check a library for arbitrary monads. And you want that, because when it comes to reasoning about code using such libraries and then applying it to a monad assembled from a stack of several other monads, you really want your type-checker around.
Ocaml's type-system is powerful enough for this, and I still reach for my monad library when writing Ocaml code. It's syntactically heavier than Haskell, but not too painful. The solution is to make all your monads into modules, which would be a bit like making every monad a dictionary and passing it around explicitly. This is basically what Haskell ends up doing with type-classes anyway, and what Gabriel Gonzalez has suggested one do explicitly:
http://www.haskellforall.com/2012/05/scrap-your-type-classes.html http://www.haskellforall.com/2012/05/scrap-your-type-classes...
If you follow this approach, Common Lisp and any other language can pull it off by making all monads into dictionaries. All you lose is the type-checking.
- deleted 12y ago[deleted]
- zak_mc_kracken 12y ago> If you have imperative state then toy uses of the state monad might be overkill What's imperative state? These are two very different concepts. Both functional and imperative code can be manipulating state, and that state can be either mutable or immutable. Haskell is often considered to be both a functional and an imperative language (see how linking do statements works). I'm guessing you meant to say "mutable state" above?
- Chattered 12y agoBy "imperative state" I mean state for which the ordering of state updates is set by the operational semantics of your language, or the execution model, or the way it ends up implemented on an abstract machine. In the case of Haskell, I mean the ordering of state updates you'd get if you used unsafePerformIO whenever you do your get, put and modify, which is generally going to be unpredictable. If I'm working in code where the operational semantics is not fully defined or difficult to reason about, I might find myself reaching for the state monad, regardless of whether my language supports imperative state (such as with Ocaml). I brought up back-tracking parsers as an example.
- nbouscal 12y agoI don't know who you've been talking to that considers Haskell to be an imperative language, but that's nonsense. Haskell is about as far from multi-paradigm as you can get. Do-notation is nothing but syntactic sugar for regular monadic expressions, which are pure functional in every way.
- tel 12y agoBecause monads allow you to basically embed "Algol" into Haskell. It's super imperative, despite it being interpreted as a pure function. I'd actually go so far as to say Haskell is quite multi-paradigm but only the FP side comes close enough to Haskell's "purity" as to make a community translation. I'd be quite willing to say that Haskell has a fantastically correct if slightly difficult to use object system. It just doesn't quack anything at all like Smalltalk or Java's.
- ruricolist 12y agoFor the record, exactly such a library already exists: http://common-lisp.net/~frideau/lil-ilc2012/lil-ilc2012.html http://common-lisp.net/~frideau/lil-ilc2012/lil-ilc2012.html Although the specific problem of state-with-backtracking would be more idiomatically solved with dynamic binding.
- hyp0 12y agoa tangent on the example of parsers that happened to be used: I found imperative mutable state made experimenting with different kinds of parsing algorithms tremendously easier. You can just say what you mean. Now, I'm sure there is a way to express it with monads (that would be simpler to reason about and confirm for correctness etc), but the first problem for me, in experimenting with different approaches, was to get my ideas out of my head and into code, and get them to work at all. If I was more skilled with monads, I might go directly to the ideal monadic solution... but I suspect I wouldn't have ideas that didn't fit well with monads in the first place. That is, (I fear) thinking in monads would restrict the breath of approaches that would come to mind... Disclaimer: because I'm not skilled in monads, I don't really know.
- tel 12y agoMonads make you be more clear than you might otherwise. Saying what you mean just means that you're used to the semantic space of your "standard imperative". This comes to play in parsers because a lot of their challenge is in properly piping around the recursive-backtracking state parts. Using monads you just create a semantic world where this recursive backtracking bit is built into the "nature" of state in your particular monad.