In a blog post form: www.unison-lang.org/docs/fundamentals/abilities/for-monadically-inclined/
@Slate245Ivanovo6 ай бұрын
Was I just tricked into watching a Haskell vid by a funny thumbnail?
@mtaur41136 ай бұрын
A monad is a monoid in the category of endofunctors.
@Slate245Ivanovo6 ай бұрын
@@mtaur4113 I always thought it to be a burrito though
@JoeTaber6 ай бұрын
@@Slate245Ivanovo The channel's profile photo agrees with you.
@jean-michelgilbert81366 ай бұрын
Yep. I have the same feeling of being tricked too. I usually avoid Haskell and FP. There's already enough new things happening in the C++ world.
@8panthermodern26 ай бұрын
Just the KZbin algorithm pushing another extremist ideology. Sure, it starts with the memes. "Monads, lol", you say to yourself. Next thing you know you are holding your scrum meetings hostage with long tirades about type theory.
@JanilGarciaJr6 ай бұрын
Just found out about ocaml's effect handlers yesterday, the timing of this video is just amazing lol Unison looks really cool, I might check it out. I think algebraic effects are here to stay from the little I saw. I honestly can see mainstream languages implementing this 10/20 years from now.
@NostraDavid26 ай бұрын
All I know about Monads (other than that they are a Monoid in the Category of Endofunctors) is that they are basically a black box that holds state (of your game, a file, anything, really). You pass that black box into a function. The function unwraps the black box and does something based on the input state, constructs a new black box to hold the new state and passes that black box to the next function. I have no idea if this explanation is even correct, but it's what my peabrain has come up with after watching 451 videos, and reading 2501 Wikipedia articles, about Monads and what REALLY TRULY FINALLY are.
@cgibbard6 ай бұрын
That's really only a description of the state monad in particular, where you implement stateful computations by using pure mathematical functions (i.e. the sort you learned about in math where there's only one possible output for any given input) by taking an initial state and transforming it into a final state along with some result. The monad abstraction also captures a broader pattern of defining some sort of "computations" having a result, where you have certain primitive operations that allow us to build a common library of "control flow" operations in terms of that. So you can, for instance, define how a for-each loop ought to work in any monad, as an ordinary library function. Then upon finding out that your parsing library defines a monad of parsers (which might in addition to implementing state, also implement backtracking), you get to make use of the for-each loop that was already defined in the library to concatenate together a bunch of parsers (and a lot of other useful control-flow-like things besides). The monad abstraction only really makes sense as an abstraction once you look at a bunch of examples. On top of that, the code for it in languages that aren't similar to Haskell (in particular, it kind of demands static typing + something like type classes that let you pick implementations of things based on the type of result they need to produce, not just the type of the input) is usually going to be ugly and/or crippled in some way which reduces the usefulness. They're super useful and good in Haskell, and I feel like this video strawmanned the monad code a good bit (look how ugly this is if I write it in a way that nobody does), but I wouldn't blame, say, a Ruby or Java programmer for not using monads, because you just don't have the right sort of polymorphism in those languages to get the benefit from it conveniently.
@samuraijosh15954 ай бұрын
@@cgibbard Monads in Haskell seemed to be designed in such a way that you're punished for even using by them even though they exist as a potential option. The fact that all of your stateful computations have to always exist in the ST monad is just so not easy to deal with. Yes, sometimes you can extract the value from ST but if only it's a simple immutable type which doesnt have the state s token embedded in its kind signature. Very very annoying abstraction in my opinion. after trying to integrate some mutable types in complex type at the type level, I just gave up and opted for immutable alternatives.
@cgibbard4 ай бұрын
@@samuraijosh1595 If the type of thing you're returning from ST has an 's' in it, that means it contains references to mutable variables. There are ways to smuggle such values out, but they are useless, because if you were to do another runST to get back into the ST monad to access them again, the 's' would be treated as distinct by the typechecker, and it wouldn't let you access them. This is what makes runST safe and doesn't cause it to just break the entire evaluation model of the language. If you want to return the contents of those mutable variables instead, you just want to use readSTRef at the end to get the values out. (If it's an array, you might instead use runSTArray.) But that said, ST is pretty niche indeed, and yeah, most of the time, you're better off just writing a functional program to compute what you were trying to compute, I super agree about that part. That says very little about whether monads in general are a good abstraction though. I think the first example of a monad which really convinced me that it's a good idea was parsing monads. You can have a type (Parser t) of parsers which consume some portion of an input string in order to produce results of type t, and combine those together using the monad operations, and stuff like forA which was ordinarily a for-each loop in stuff like IO or ST, turns into a way to concatenate a bunch of parsers together and collect the results. Other really nice examples often have to do with contexts where you want some effects, but can't or don't want to allow all of them. A monad for doing database or memory transactions that might need to be rolled back and retried later might want to prevent various other sorts of effects from occurring because you can't un-fire the missiles. I do a lot of work with functional reactive programming stuff using Reflex (building web and mobile apps mostly, some desktop on occasion). In that context, we have some monads where the actions are implicitly a function of the present time (but what that time actually is, is never mentioned or specified because the system as a whole at a low level is implementing things with IORefs and carefully providing the illusion that updates happen in lockstep globally and dealing with all the simultaneity). There, the monad operations serve as a way of sticking together things which vary over time in various senses to make more complicated things which vary over time. The simplest of those is probably (Behavior a) which is the type of things which vary over time, and have a value of type a whenever you'd care to look, but can't notify you of when they change: it's consistent with the laws of the system that they may even change continuously. Another is (Dynamic a) which is like a step function that only changes at discrete moments in time and you can tell when. Those are both monads. The real point of it all is that this idea of having a type of computations of some sort that will later be run to produce values is a fairly common functional programming abstraction. By recognizing it, we get to reuse things like all the control flow stuff in Control.Monad and gadgets like monad transformers, without needing to rebuild that stuff for each new monad, so it's quicker to get these sorts of domain-specific libraries fleshed out.
@georgH6 ай бұрын
The thumbnail cracked me 🤣🤣🤣
@capability-snob6 ай бұрын
My goodness. A video on algebraic effects 😮 Nicely done.
@OhsoLosoo6 ай бұрын
No please guys don’t change anything. I’m just starting to get the hang of functional programming, I recently have began to study category theory & its implementation in computer science 😭😭😭
@impurepics6 ай бұрын
You don't need to study category theory to write/understand functional programming. I would only recommend category theory if you think it's fun.
@nanman_chief4 ай бұрын
I'm not sure if this comment is a joke (sorry, I often misunderstand humor on the internet, so I need to check). If it's not a joke, I have some good news for you: Effect handlers are essentially based on category theory. They are just so well-packaged that you don't need to know what Yoneda lemma is to happily use them for programming. If you're deeply interested in the theory, you can read Gordon Plotkin papers "Algebraic Operations and Generic Effects" and "Handling Algebraic Effects".
@justinhj13 ай бұрын
Beautifully produced and content rich, thanks!
@woobilicious.6 ай бұрын
Your assessment that Haskell is non-strict and Monads "help" is wrong, The point of a Monad is to handle side effects/passing the "world" around on the side in a pure language, they allow you to turn a function "(World, a) → World" in to a "a → (World → World)", monads allow you to write functions that return functions with the world as the only argument, the IO Monad is not strict and only some calls force evaluation, the best way to think about it is that IO is a output based promise system, `a ← readLine` doesn't run *until* you use the `a` in some sort of output, they do a poor job of sequencing effects. And you will get intermittently familiar with forcing evaluation in the correct order using bang patterns (using !), unboxed types and `seq` and `deepseq` all have varying effects on thunk evaluation ordering. It's probably the biggest pain point of Haskell.
@apteropith6 ай бұрын
well, it's true for side-effects that are internal to haskell, where it knows all the dependencies, but that's a fair point that the language would need still extra help with IO side-effects, since there's little way for it to tell if one IO action is meant to be _externally_ "dependent" on another i wonder what the best way to handle that is! haskell is very neat and demonstrates some very good ideas, but i find it deeply imperfect in some spots (so i very quickly lost most of my interest in it, oops)
@samuraijosh15954 ай бұрын
@@apteropith the monad abstractions Haskellers came up with to handle mutable types are fine in theory/concept but they're executed so badly in my opinion.
@nythrox30476 ай бұрын
Thank you for bringing up the important stuff
@apteropith6 ай бұрын
i learned about monads in haskell a few years ago; while i did appreciate the power of the very fancy wrapping & unwrapping of values which monads can provide, my biggest takeaway was actually that the do-blocks with the bind operators are just a form of continuation-passing style, and should never have been confined to monads the bind operator really should default to simpler function-composition when a monad is not present; there is little reason for it not to, and not doing so damages the flexibility and utility of the do-block's syntax - i might go so far as saying it damages the elegance of the language
@locker476 ай бұрын
Could you show an example of converting a piece of code that uses monadic effects into algebraic effects and show the pros/cons of each? I'm trying to wrap my head around the ergonomics of tagless final and algebraic effects (e.g., Cats vs. Kyo), and when should we prefer one over the other. If there is a blog post on this I would love to read it!
@generalyoutubewatching5286Ай бұрын
This one video made me subscribe!!! Love how u pointed out that Haskell was lazy and hence needs monad for io
@impurepicsАй бұрын
@@generalyoutubewatching5286 Thanks, I’m glad you enjoyed it; bunch of people hated that part 😀
@DrewryPope6 ай бұрын
Laziness in Haskell on the Tweag channel is very good
@impurepics6 ай бұрын
Agree
@ywenp6 ай бұрын
5:00 That is a bit of a strawman and you know it :) That's what the syntactic sugar of Haskell's do-notation is for, and it's very straightforward. Don't get me wrong: the rest of your points remain valid, but the drawbacks of using monads don't lie in the syntactic department. You could say though that's is a bit of a bummer to have two different syntaxes for pure code and monadic code, but this gives the advantage of making it immediately clear when some part of the code is not using a standard control flow (which is kind of an important thing to know when you look at code). 15:34 If by "static control flow" you mean "being able to see the whole graph of computations before actually running it" (given you use build systems as an example, I have a sense this is what you mean), then you cannot do that with Monads either. Monadic computations are opaque by essence, they produce a dynamic computation graph just like direct style. You need other control flow structures for that (namely Applicative functors or Arrows).
@impurepics6 ай бұрын
Any extra syntax (or even sugar) is a cognitive overhead. And some people think that do-notation is even worse. We emulate strict languages and the idea of execution during the evaluation (one more thing to think about) to build programs as values, which will then be executed. Another syntax - another level overhead. You're right. In the video, I said monads "and friends" because I didn't want to bring another player all of a sudden. I realized it wasn't a good idea, in the blog post I explicitly bring up Applicatives.
@ywenp6 ай бұрын
> Any extra syntax (or even sugar) is a cognitive overhead. Yes, it's true. But it's just one criterion out of many over which to evaluate such a design choice. In any case, my point was that it does the job of tidying up monadic code so you don't have to do the heavy lambda-juggling you were showing.
@isodoubIet6 ай бұрын
If it were a strawman, there wouldn't be as many monad tutorials as there are, nor would there be tens as many people commenting some variation of "I still don't get it" underneath every single one. One of the most fun things to do is to ask what are Monads in a Haskell forum and watch the magic happen as people start fighting over one another's misconceptions.
@zackyezek37606 ай бұрын
What modern programming languages really need is explicit syntax for defining tasks- atomic chunks of work with explicit inputs and outputs, the dependencies between them, plus any other specific runtime or state machine conditions the actual machine running the code should honor (e.g. error handling). Basically, doing for the state machine of a program- the control flow, async logic, parallel processing- what the introduction of objects (“classes” or “object oriented programming”) did for the data. Manually writing threads or low level async handoffs like semaphores and locks is really the state machine equivalent of directly writing assembly. Monads are like the structs in the original K&R C; they’re a significant and powerful improvement upon straight assembly and primitive types, but far from the massively more powerful (and complex) full blown objects of C++ or Python classes. It’s why their rampant (ab)use is everywhere, why so much custom boilerplate is piled atop them, and why a lot of that code is reminiscent of the old school C boilerplate you write to obtain de facto vtables and ‘member functions for C structs. Because it’s the equivalent of full classes that we need for the state machine, and we don’t have those yet.
@i-am-the-slime6 ай бұрын
Very good effects. I handled them like a champ.
@jenreiss31076 ай бұрын
I really like the fused-effects library, as fusion laws allow the effect handler to fuse effect types so that evaluation only requires a single AST traversal, rather than the O(n) for more standard free monads. granted, it is built on a giant tower of abstractions that is very tough to grok, but once you do, it is incredibly powerful
@poklet6 ай бұрын
Do these methods compose well? For example if an existing codebase was written in a monadic style, is it possible to add code with Abilities or Direct-Style? If they do compose, what’s the mental overhead like in juggling all these styles in one code base?
@impurepics6 ай бұрын
Depends on the language/implementation. Shouldn't be a big problem, as long as there are functions to convert from one to another. For example, in Unison, you can convert the "monadic" Either to the Exception ability and vice versa. So, if you have a function that returns an Either and another that has Exception, and want to use/compose them together, you might need to convert one of them first (e.g., using Either.toException). But, yeah, mixing styles always comes with overhead. share.unison-lang.org/@unison/base/code/releases/2.20.0/latest/terms/@5mqjoauctm02dlqdc10cc66relu40997d6o1u8fj7vv7g0i2mtacjc83afqhuekll1gkqr9vv4lq7aenanq4kf53kcce4l1srr6ip08
@Heater-v1.0.06 ай бұрын
Wow! I have been programming for 40 years. On all kinds of projects from time embedded systems to desktop CAD systems. In all kind of languages from assembler up. Ten years ago I first heard the word "monad". Despite multiple efforts at understanding it I still don't get it. Now this, I have no clue what the words even mean or why one would want such a thing. Luckily such cognitive overhead is not required to actually get useful things done.
@hath9956 ай бұрын
Monads are the minimal structure needed to do function composition of wrapped/decorated data types. You can compose easily a function from integer to string and a function string to boolean to get a function from integer to boolean for example. Now if you had functions from integer to Boxed and one from string to Boxed, where Boxed is some container type like Array or Optional then you can't compose these functions naturally. Roughly a monad is just an interface on your objects that provides a method called chain or flatMap that can take a Boxed and a function from T to Box to produce a Boxed.
@diribigal6 ай бұрын
This reminds me of "Hold" in Wolfram Language where delaying evaluation (really substitution) is not weird, but the syntax overhead is a lot compared to the parentheses and ticks shown in this video. I have to check out Unison now!
@federicoagustinsawadyoconn27165 ай бұрын
Some things I read in the comments or see in the video make me realize that some poeple analyze Haskell as if its computing model were the same as other traditional languages, when it is not. Referential transparency, in the computing model that Haskell chooses to have, is extremely important, so it is not that optional. That is the main reason why the language is lazy. And it is the main reason why one also chooses to program in Haskell. Algebraic structures like monads or applicative functors are excellent in terms of maintaining equational reasoning more than other options, so they are not criticizable in the same way as a feature in a imperative language. They are not just a feature that solves something from a utilitarian point of view neither, because they are a mathematical solution for mantaining clear reasoning about pure code, which in Haskell is more important than in other languages. I know that many want features in Haskell that are also utilitarian, which is not bad, but please understand that the language was not designed for that, so you have to be aware of what I mentioned before when analyzing some of the pain points of the language.
@hantuchblau6 ай бұрын
Great video! I still find it funny that java has almost everything you need. Checked exceptions for effect tracking, thread local state for handlers, the new virtual thread stuff for control flow manipulation. Pity java surface syntax cannot write down type unions in most places, though. One point I didn't understand is why 'user-defined effects' were rated better for Abilities than for Monads. In my experience multishot delimited continuations are hard to make efficient, so you gotta work much harder to build good nondeterministic effects. Many implementations just give up and forbid multishot effects entirely. With mtl-style final embeddings CPS nondeterminism just works.
@ZeroG6 ай бұрын
I do not understand what is meant by "effect handlerl
@impurepics6 ай бұрын
Sorry, didn't have time to go into it. Here are a few good pointers: * www.unison-lang.org/docs/fundamentals/abilities/using-abilities-pt2/ * v2.ocaml.org/manual/effects.html * koka-lang.github.io/koka/doc/book.html#sec-handlers * effekt-lang.org/docs/concepts/effect-handlers
@ZeroG6 ай бұрын
How is this different than what I can do in Swift already, using closures?
@capability-snob6 ай бұрын
Effect handlers may or may not choose to return back to the caller, hence the comparison to exception handling and call/cc.
@JanilGarciaJr6 ай бұрын
How is it similar to closures?
@u9vata6 ай бұрын
Good content - but for solving the same things, I would any day take somthing like zig comptime instead or metaprogramming in general... Too taxing on the programmer to do it these ways still.
@estebanmarin0026 ай бұрын
wow, loved the explaination
@hansisbrucker8136 ай бұрын
I wonder if it can be implemented in Common Lisp using macros 🤔
@mskiptr6 ай бұрын
I'm at 7:00 and I have to say it's a really nice overview, but I absolutely cannot agree with the conclusions so far
@wildwestrom6 ай бұрын
I gotta figure out how I could translate this concept into Rust code. Maybe it'll result in better code?
@dansheppard29656 ай бұрын
Mercury's "modes" always seemed a neat middle ground for side-effects. I'm not sure why they haven't caught on.
@Nikolas_Davis6 ай бұрын
2:05 shouldn't these be "\_" instead of "\\_" ? (Absolute noob in haskell; still, I think that's a typo)
@luvincste6 ай бұрын
i didn't really understand much of this
@herrbonk36352 ай бұрын
You are not supposed to.
@hindigente6 ай бұрын
Went in thinking this was about category theory. :D
@mattmmilli82876 ай бұрын
This is just a methodology that applies to any language ?
@maxmustermann55903 ай бұрын
I was told you were the burrito made me spit out my coffee my guy
@8panthermodern26 ай бұрын
Just the KZbin algorithm radicalizing another generation
@angeloceccato6 ай бұрын
Figoooooo, great video¡¡¡
@MikkoRantalainen5 ай бұрын
15:52 I would argue that neither monads for "abilities" are teachable. Definitely not easy to teach as direct style procedural programming.
@BenHutchison6 ай бұрын
I'm sceptical of the claim that writing effect handlers is easier than monads. Better leave such claims for a future video where you have time to go into the topic and hopefully show some evidence for your claims. Which I personally think will in the long arc of history end up being recognised as "about equivalent" to monads.
@impurepics6 ай бұрын
Yeah, I'd like to go deeper into the topic. For now, I assumed that an average viewer/reader either has no experience writing production/real-world monads or already knows that it's not that easy (I'm not talking about monad-tutorials-like monads). So, the bar for the effect handlers is relatively low. Unison docs already has a good section on writing handlers: www.unison-lang.org/docs/fundamentals/abilities/writing-abilities/
@asdfghyter6 ай бұрын
in my experience they are way easier to write. it’s generally straightforward, while monad transformer implementations are finicky and easy to get wrong (c.f. the many “ListT done right”) but the most important advantage in my opinion was missing: unlike monad transformers, effect systems generally aren’t order dependent, so you don’t need to be careful about stacking the transformers in the right order
@Taylor-rx4yb6 ай бұрын
I love monads! But I am also a mathematician and I'm realizing this video isn't actually for me lol
@TaranovskiAlex6 ай бұрын
"a guy in a lab coat with a shank"...
@mojeimja6 ай бұрын
this all looks horrible :)
@herrbonk36352 ай бұрын
Indeed. As complex as possible, instead of the opposite.
@vpatryshevАй бұрын
This talk is really confusing, since it does not give an impression that the speaker knows what monads are. Weird.
@impurepicsАй бұрын
@@vpatryshev knowing what monads are and knowing why monads are used are two different things. I assumed people watching are familiar with the former, and the later is important for talking about a bigger picture
@JorgetePanete6 ай бұрын
I'm having a really hard time understanding your words and the automatic subtitles aren't helping
@impurepics6 ай бұрын
I'm working on the blog post version. I'll share in a few days.
@impurepics6 ай бұрын
You can read it here: www.unison-lang.org/docs/fundamentals/abilities/for-monadically-inclined/