4 ms·
Something I've always wondered, you may be able to help with - why are monads? I.e. what is the problem they try to solve? I use objects and first class functio
by chadcmulligan 9y ago
Something I've always wondered, you may be able to help with - why are monads? I.e. what is the problem they try to solve? I use objects and first class functions and they're pretty useful, occasionally even do a bit of currying (mainly because I think - ooh I can do a bit of currying here :-)), so how would Monads make my programs better/ easier etc. I've heard they can sequence your IO operations but in non functional languages thats not a problem. I feel there must be something they do that I'm missing so any pointers would be appreciated. Thanks.
Edit: like the two things I spend most of my day writing code for are UI stuff and database code - can monads do anything for me there?
- KirinDave 9y agoSure. This is probably a much more useful question than "what". For Haskell, Purescript, Agda, Idris and other languages that like to rely on them, Monads represent some cool properties that make code extremely reusable. 1. Monads have a uniform, universal description of sequenced code. They can model essentially any form of computation that depends on its input and known state. This makes them a very nice level of abstraction to write highly generic tools. As an example I wrote about here awhile ago (https://news.ycombinator.com/item?id=16831985 https://news.ycombinator.com/item?id=16831985), it makes it easy to write async code execution strategies without ever even considering any aspect of the code other than that it's sequenced. 2. Monads describe behaviors, but a subtle point is that in a language with generic code (paramaterized or higher-kinded types, etc.) Monads let you write code to a GENERIC monad. As an example, what does this code do? data SomeThing = SomeThing { name :: Text, age :: Int } makeSomeThing :: (Monad m) => m Text -> m Int -> m Something makeSomeThing nameE ageE = do name <- nameE age <- ageE return $ SomeThing name age This code Makes SomeThing (and yes, I could write this more neatly as `liftM2 SomeThng`, and often we use Generics to mechancially derive this code, but I'm making a point here). But we haven't discussed anything except that: a. We are given effects to get name and age. b. We seqentially use those effects to produce two values. c. We then have an effect to produce SomeThing. That's pretty amazing, if you think about it. Depending on what the monad is, we could be calling over the network, or executing things in parallel, or parsing it off of stdin. We could use the Maybe monad to represent values that may be missing, or we might use Envy (https://hackage.haskell.org/package/envy https://hackage.haskell.org/package/envy) to read it from the environment. Monads give you a way to parameterize the structure of the logic you need to describe a task and make statements within that logic. This is why monadic programming tends to get really addictive. And as time has gone on, everyone has found new compiler techniques to make this kind of code easier AND more powerful. The next generation of programming languages folks are researching focus on Dependent Types (hi Agda and Idris) and Linear types (hi Rust and Pony and Idris), which let us take monads even further, allowing for a princpled approach even with previously complex tricks like interleaved effects, sophisticated type indexes, and consistent resource management. > Edit: like the two things I spend most of my day writing code for are UI stuff and database code - can monads do anything for me there? I just posted this code elsewhere, I just wrote a for-production Haskell microservice that I made generic over the database actions (type "p" in the code). This code does not know what database OR header validation scheme it's going to use, only that we've explained how to make CanValidate and Patchable actions in our action monad. This is better than writing for DI or mocking, DI and mocking usually couple your tests and underlying code structure deeply. This is Faking, where I have a trivial alternative service stubbed in so I can test my API logic without appealing to a database, and then run integration tests on my database actions separately. https://gist.github.com/KirinDave/9b4380376f9f748bcf0f8440decae517 https://gist.github.com/KirinDave/9b4380376f9f748bcf0f8440de... You might also see that I have "ValidAction" and "BaseAction" and there is a "validationHook." The framework I chose here lets me use "hooks". These hooks help the compiler check that I only run my database actions inside a Validated context, and don't try to validate again once I've already Validated. More precisely, they're helper functions to let us pretend indexed monads are normal monads. Here are sample implementations of CanValidate and Patchable from unit tests from that code so you can see the constraints in play. https://gist.github.com/KirinDave/fe317bffb5e4b2f1316c207325be2d1d https://gist.github.com/KirinDave/fe317bffb5e4b2f1316c207325...
- chadcmulligan 9y agoThanks for that, I can see these things would be useful - but are they a 'killer app'? Like it seems a lot of work to figure out the abstraction to build the monad, when I don't really need to do this, cause I only have to do this one thing. Or are there a bunch of monads people have already figured out? and I can say when I strike this problem I can use this monad write a few lines of code and go home? Maybe thats the goal? I can see technically its interesting but I can't see a really good reason to spend a lot of time learning this (and I am curious about them). Or are these tools for compiler writers and they'll filter down to us mere mortals? Like Swift can define types as optionals, which sort of looks like the Maybe in haskell (to me any way). Edit: Like I started out as a C programmer, and then objects came along and I could see that would be useful because it localised the namespace among other things, then generics came along and they were instantly useful, languages have a lot of functional operations like first class functions and they're useful. Like all these things seemed obvious that they'd help write good code, Monads I just can't see why they're good - you've given a couple of examples and they seem useful, though they're not things I can't do with other language constructs, perhaps not as elegantly. I'm wondering if I'm missing something huge? :-)
- deleted 9y ago[deleted]
- KirinDave 9y ago> Thanks for that, I can see these things would be useful - but are they a 'killer app'? Like it seems a lot of work to figure out the abstraction to build the monad, when I don't really need to do this, cause I only have to do this one thing. Most of the core monads are already done. You make new ones to define new compositions of new ones and bring in new features. I've only ever needed to make a genuinely novel monad once. You often don't even make custom monads, you make custom typeclasses that explain how to do your work within a monad, and then pick the ones you want. > and I can say when I strike this problem I can use this monad write a few lines of code and go home? Maybe thats the goal? It is. But as I said, a lot of time what you're actually dealing with is a custom transformer stack with either Identity or IO at its root. So you just write generically and specify what you want. In practice, it's not very difficult. > Like Swift can define types as optionals, which sort of looks like the Maybe in haskell (to me any way). They are. Good example. > Monads I just can't see why they're good - you've given a couple of examples and they seem useful, though they're not things I can't do with other language constructs, perhaps not as elegantly. What's incredibly hard to do is write code that's generic in this axis. There are other examples exercising these principles and pretty amazing things can fall out of that. For example, lenses use a weaker abstraction (functors)and they can make a function that depending on how its' called, either gets a value inside a struct or rebuilds the struct with a new value. Pretty amazing! > I'm wondering if I'm missing something huge? :-) Maybe. But as many people have noted, Haskell is a comittee language that is surprisingly good as an accident of its features all happening to stack together in a somewhat unplanned way. So there is more to the story than this, but this IS a pretty unheard-of story.