10 ms·
Monads make a lot of sense in a pure functional language like Haskell, because it allows you to program in an imperative style when you need it, and keep the re
by olavk 9y ago
Monads make a lot of sense in a pure functional language like Haskell, because it allows you to program in an imperative style when you need it, and keep the rest of the program pure and functional.
The benefit of State and IO monads is not that you can use them everywhere so you now have an imperative language. The benefit is you can explicitly delimit their use, and you still get the "easier to reason about" for the rest of the code.
For languages which already supports mutable state everywhere by default it does not make much sense to use monads for this.
- paulddraper 9y agoAgreed. The "islands of immutability" approach.
- willtim 9y agoI agree, but Monads also simplify non-blocking concurrent programming, allowing users to think sequentially, see F# Async and Haskell IO. C# had to add Async/Await support in the compiler and I would argue it is not as pleasant as the F# version using Monads.
- seliopou 9y agoThe separation of pure and impure code in Haskell isn't something inherent to monads but is instead a side-effect (hah) of the typing rules of the language. It's easy to see how this separation need not hold when using monads (look at any monad library in virtually any other language), but more importantly there are ways to accomplish this separation without the use of monads (an effect-tracking type system is being developed along side OCaml's algebraic effects/multicore project).
- aaron-lebo 9y agoDoes it make sense to view IO/State monads in Haskell as analogous to unsafe blocks in Rust?
- quchen 9y agoI don’t think so. - IO can be seen as a tag added to a type that brings »the outside« into scope: the console, the network, current time, the harddrive. In Rust, these are always available, regardless of the type of the expression at hand. - IO is »viral«, in the way that things that touch IO will become IO as well; there is no way to remove IO to yield a pure value. If a function in Rust contains an unsafe block, is the whole thing unsafe? I don’t know enough Rust, but I think it’s not.
- steveklabnik 9y agounsafe is not viral; if it was, everything would be unsafe. An unsafe block is the boundary where you tell the compiler "I've got this bit", and so it trusts you and considers it safe.
- whateveracct 9y agoFunnily enough, “unsafe” in Haskell (e.g. unsafePerformIO) is the same way. Not viral so as to say “trust me.”
- skolemtotem 9y agoNo, that does not make sense. Rust's unsafe code lets you do some things that could violate the compiler's expectations, and making sure that you're aware that you need to manually enforce those invariants. Haskell has some unsafe* functions that are exactly like that, too, such as unsafePerformIO, that are analogous. On the other hand, the IO and State monads are completely safe-to-use, using a simple abstraction to represent impurity in a pure language.
- bad_user 9y agoMonads are not directly related to handling side effects. Or to the famous IO that you're refeering here. What a Monad does is to force sequencing by creating a data dependency. Speaking of IO ... In an imperative program you get guaranteed ordering of those instructions, but that ordering is thread local, meaning that the compiler, the runtime, the kernel, the CPU are all free to reorder instructions for optimal execution and ordering between threads is forced via memory barriers, which is in fact incredibly error prone. In an FP language such as Haskell you get the extra problem that the compiler is even more free to rewrite and execute your code in any order it sees fit due to non-strictness and to referential transparency. What the IO monad does is to "suspend side effects" and to force ordering on evaluation. And guess what, the IO monad is useful even in your average imperative program for describing concurrent logic. Here are the implementations I contributed to: 1. https://monix.io/docs/2x/eval/task.html https://monix.io/docs/2x/eval/task.html (Scala) 2. https://github.com/typelevel/cats-effect https://github.com/typelevel/cats-effect (Scala) 3. https://funfix.org https://funfix.org (JavaScript) If you've ever worked with JS Promises, think of IO as a non-broken, pure, awesome alternative. And this is just IO. There are other monads as well. List is a monad, Option and Either are monads ;-) --- I recommend you let go of your misconceptions and do some learning because this is a freaking useful concept.
- olavk 9y ago> I recommend you let go of your misconceptions and do some learning Thank you for the advice! Monads seem to have some kind of smugness creation field. I know there are other monads beside State and IO, I was specifically referencing the argument in the linked article which was about using monads for mutable state, basically turning the code into imperative style.
- bad_user 9y agoThat wasn’t smugness. I only replied to you because those were my thoughts from 5 years ago. And I was wrong. And yes, it’s a little troubling that such awesome concepts are not penetrating the mainstream, being so misunderstood. I blame the available leaning resources. It took the GC 30 years after invention to become mainstream. Functional programming, actual functional programming, apparently takes longer than that.
- jordigh 9y agoI really like D's approach instead. A function declared pure can have no side effects but it can do whatever kind of mess it wants within its own code. It can have loops, assignments, reassignments, memory allocations, but it can't mutate variables outside its scope nor can it call any impure functions. I find this is a very practical compromise that lets you have the good parts of purity without ever getting the urge to write a blog post about monads. https://dlang.org/spec/function.html#pure-functions https://dlang.org/spec/function.html#pure-functions
- olavk 9y agoThis is definitely cool, but monads is a more general concept. It can be used to isolate side-effects, but can also be used for many other things.
- tome 9y agoThat's what Haskell calls "ST" and is far less powerful than the general notion of monads.
- quchen 9y agoHaskell has the ST type for this, which is a stripped version of IO in which we can still make proper mutable inplace updates like in other languages, but there is a »runner« function called »runST«, which guarantees that the computation it contains does not leak any state to the outside – in other words, »runST <impure>« is pure from the outside. This allows embedding of mutable algorithms, e.g. inplace sorting of vectors, into pure code.
- gowld 9y agoThis is "const" in c++
- jordigh 9y agoI don't think this is the same. My C++ is getting rusty, so correct me if I'm wrong, but making a function const is mostly about making the "this" pointer const. A const function can still mutate global variables or call non-const functions, such as operator<< on cout. A pure D function can do neither of those things.
- grdvnl 9y ago> The benefit of State and IO monads is not that you can use them everywhere so you now have an imperative language. The benefit is you can explicitly delimit their use, and you still get the "easier to reason about" for the rest of the code. It is also important to note that apart from providing the ability to write imperative code, monads encapsulate computation. In my understanding, this is where their use shines. Getting to wrap values in such contexts in certain imperative languages could be tedious. Using a monad, one passes around the value within the context of the monad. There is a computation(aka context) that is associated with the value in the monad and that computation is performed before a value is yielded.
- raverbashing 9y agoThe weird thing is that you end up with something that looks like 2 different programming languages in one (talking about Haskell) Also, Haskell's implementation of it is a bit weird an unintuitive (and the shortcuts just hide the messiness) Given that you need state to interact with the outside world, making it more complicated in that essential area makes the learning curve harder
- olavk 9y agoDo-notation does look different, but it is similar to the statement/expression distinction which is present in most imperative languages.
- kqr 9y agoMonad is practically synonymous with choice. Any time you multiplex on whatever is represented by a thing to choose a different thing, you're doing a monadic operation whether you want to or not. The difference is whether or not your language has libraries for this or you have to program it yourself every time.
- gmfawcett 9y agoConditional evaluation might be a use-case of monads, but that doesn't make them synonymous. "getLine >>= putStrLn" (read a line from stdin, write it to stdout) is a fine Haskell expression of the IO () type, but nothing in it resembles a choice. Monadic expressions can be extremely, boringly linear.
- kqr 9y agoAre you sure? Of all the messages the program could have printed, of all the I/O actions imaginable, the program somehow made a choice that was not hard-coded, but based on my input! The expression multiplexes one I/O action (what to print) based on the result of another (get input from user). That's choice! Edit: Just realised what might be confusing. putStrLn is not an I/O action in and of itself. It's a function that multiplexes on several I/O actions based on the input value. However, crucially, that input value is pure, and thus can only be hard-coded (maybe through a bunch of indirections, but ultimatedly statically determinable.) Monadic bind is what lets us depend on another I/O result.
- gmfawcett 9y agoYou're stretching. :) But even if I accept the point you're making here, that doesn't make monads synonymous with choice. Every choice is not a monad, and every monad is not a choice. This is far too reductionist. Is there no choice involved in monoids, arrows, for example? What makes monads special in this regard? And what about I/O in languages that cannot implement these concepts?
- tome 9y ago> Monad is practically synonymous with choice. Arrows also allow you to "multiplex on whatever is represented by a thing to choose a different thing" so you'll have to be more precise!
- Tarean 9y agoThere are some monads (or things close to monads) that are quite common in imperative languages. Java has - CompletableFuture - Optional - Stream - dependency injection can be seen as a monad
- deleted 9y ago[deleted]