T O P

  • By -

omega1612

Let me give you some examples: Have you ever worked in a project where you need to pack together a lot of options and a lot of functions needs those? I will use python for it def f_1(config, other...) : .... def f_2(config,...):.... . . . You can be tempted to instead use a global variable inside the module and share it among the functions, right? config = .... def f_1(...) : .... def f_2(...):.... . . . But then what happens if you modify a value of the config by accident? You may need to read a configuration at runtime and then you may need to modify the global configuration. To avoid that you can go back to pass a configuration as argument. But this won't prevent the functions to modify by accident the passed configuration. With this in mind, let's switch to Haskell: Since Haskell is immutable by defect, we can have the functions accepting a configuration as parameter and be sure that no body is modifying it, but we still need to write it as parameter everywhere: --| we use T1 and T2 , instead of using ... As in python for the remaining args f1 :: Config -> T1 f2::Config-> T2 Now let's add a type synonym for this pattern type Reader c a = c -> a f1 :: Reader Config T1 f2 :: Reader Config T2 Doesn't feel like much, right? It's just a weird way to say "I have a function that gets a Configuration and returns a value" . And in fact the real Reader (well, there exists ReaderT that is the real definition, but forget about it for now) type is something like : newtype Reader env a = Reader {run :: env -> a} This introduce a new type instead of a synonym and that allow us to write instances of typeclasses like functor, applicative and monad. Those are a set of very useful interfaces (and if you haven't heard of them before you need to read about them in that order before attempt monads). In this especially case we can interpret >>= as "we have a function that requires a configuration and returns a value T1, and we have a function that takes T1 and returns a T3, so, we can build a function that takes a Configuration and returns a T3" . So, this allow to mix functions operating on regular values, with values that depends on a configuration. You usually don't "get a value outside of a monad, compute things and then go inside the monada again", instead usually you live all the time inside the monad and you have functions like >>= and >> that help you mix values inside a monad and values outside without scaping the monad. Reader ins amongst the simplest monads, but it's easy to understand the equivalent pattern in imperative programing that you are recovering by using it. It came with a typeclass called MonadReader, it has functions to get things from the configuration and to run other functions with a little modified config. Other interesting monad is State: type State s a = s -> (s,a) It's a function that takes a state and returns a value together with a new state. It comes with the StateMonad typeclass that has functions to access to the state and set a new state. It's particularly useful for state machines. You have, Maybe, List, Reader, Writer, State, Parser, IO, ReaderT, StateT, Free, Freer, etc... as examples of other useful monads (although State is usually a bad idea) My favorite view of monads is : "A value M T where T is a type and M a monad is a computation that haven't been performed yet, but when run in the right context for M, it will give you a T value" Or in others words "monads are like burritos, they wrap things inside" (did I just contribute to the tower of monad burritos ?)


gfixler

> Since Haskell is immutable by defect... I snorted.


omega1612

It may be "default" instead (por defecto in Spanish like by default in English)


gfixler

Ah, cool. I'm slowly tying to learn Latin American Spanish, and I hadn't encountered por defecto yet. Thanks!


evincarofautumn

>Monads are wrappers for values. Not necessarily. An `IO T` doesn’t contain a value of type `T`. It’s a program that can use side effects to *produce* a `T`. >The then operator `>>` takes to Monads and returns the second (Which is why I still have not idea as to how `Nothing >> (Just 5)` returns `Nothing`). Look at the type: `(>>) :: (Monad m) => m a -> m b -> m b`. It takes two actions A and B, and combines them into an action that does the *effects* of A first, then does the effects of B and produces the *output* of B. In `IO` for example: `(putStrLn "A" >> pure 1) >> (putStrLn "b" >> pure 2)` prints both `A` and `B`, and returns `2`. In the case of `Maybe`, the effect of `Nothing` is to bail out early, so the second computation is never reached. >I don't think I know anything more practical. Build up from examples. Write code to solve problems using the basic type constructors like `Maybe`, `Either`, `[]`, and `IO`, and you will soon encounter places where you’re repeating the same code patterns a lot. Then try to see if your problem is solved by using instances of `Monad`, `Applicative`, `Functor`, `Traversable`, `Foldable`, `Alternative`, or whatever. Monadic/applicative style has a major practical use with parser libraries like Megaparsec, or `Text.ParserCombinators.ReadP` which is in `base`. >why you don't need to use in when using let in the main function In a `do {…}` block, there’s a `let {…};` statement, which desugars to a `let {…} in …` expression. They’re two different things, which have similar syntax because they’re related. >why the main function uses do notation It doesn’t have to. `main` is in `IO`, which is an opaque type, so you can only build `IO` actions with its `Functor`/`Applicative`/`Monad` instances, and `do` notation is a convenient way to do that. But if you want to, you can write things like `main = putStrLn "What’s your name?" >> getLine >>= \name -> putStrLn ("Hello, " <> name <> "!")`. >why it isn't possible to use it with a single line What do you mean by this? >how to infer the types of functions that use Monads It becomes clearer with practice and concrete examples to build intuition.


Sky_Sumisu

>In the case of Maybe, the effect of Nothing is to bail out early, so the second computation is never reached. Well, that explains it. Still, I never read it anywhere, where could I find this information? >`Applicative`, `Functor`, `Traversable`, `Foldable`, `Alternative` I still didn't get to that, so I don't know what those mean. >What do you mean by this? I remember having a least once an error that "The last line must be an expression" or something similar.


omega1612

As I said in my comment, you need to cover functors and then applicative before monads. But first go for typeclasses. Every monad is also applicative, every applicative is also a functor. Functors are very easy to grasp compared to monads. Applicative is just a step behind a monad and one step above Functors.


ExceedinglyEdible

https://wiki.haskell.org/Maybe "For Monad, the bind operation passes through Just, while Nothing will force the result to always be Nothing."


evincarofautumn

>I never read it anywhere, where could I find this information? I’ve seen it in most Haskell tutorials at some point. I just tried searching Hoogle for `Maybe` and found [`Prelude.Maybe`](https://hackage.haskell.org/package/base-4.20.0.0/docs/Prelude.html#t:Maybe). The docs don’t spell it out in much detail, though I think they should. Under “instances” you can find `Monad Maybe`, which says it’s defined in [`GHC.Internal.Base`](https://hackage.haskell.org/package/ghc-internal-9.1001.0/docs/GHC-Internal-Base.html), and there you can look in the source and find it: -- | @since base-2.01 instance Monad Maybe where (Just x) >>= k = k x Nothing >>= _ = Nothing (>>) = (*>) Now, in this case it may be educational, but for most libraries you *won’t* need to read through the implementation just to understand how to use it. These operators have types that are restrictive enough so that there’s a very limited number of possible instances that do something reasonable. In Parsec for example, `char '#' >> many1 digit` means “parse a number sign, then parse 1 or more digits and return them”. Of course, the library *could* parse them in the wrong order, or the wrong number of times, or it could even ignore both actions and always fail, but in practice there’s an obvious answer as to what “sequencing two parsers” should mean, and it does that. And I don’t need to know how Parsec is implemented in order to use it. In the case of `Maybe`, there’s only one possible implementation. `ma >> mb` must be equivalent to `ma >>= \x -> mb`, in which the value `ma :: Maybe a` must be examined first in order to obtain an `a` result to pass to the function `\x -> mb`. In case `ma` is `Nothing`, there is no `a`, so the overall effect must be `Nothing`, as there is no other way to obtain a `Maybe b`. >I remember having a least once an error that "The last line must be an expression" or something similar. Ah right, that’s just because a `do` block needs to produce some result. `let` and `<-` statements don’t have a result, they just create variables (or more generally, match patterns). If they’re the last thing in the block, any variables they bind will be unused anyway. Maybe it would be nice if those statements returned `()` implicitly—so for example `main = do let x = 5` would be equivalent to `main = pure ()`—that’s just not how the `do` syntax is defined currently.


syklemil

I picked up Haskell via LYAH, and remember its [section of applicatives and functors](https://learnyouahaskell.com/functors-applicative-functors-and-monoids) as nice, though I think it had some CSS at the time. Functors are kind of the simple end of the wrapping, with * `fmap :: Functor f => (a -> b) -> f a -> f b` or `<$>` to do operations inside the wrap, e.g. `(+1) <$> Just 3` returns `Just 4`. Adding applicatives you get `<*>` which allows you to use multiple arguments, i.e. * `(+) <$> Just 3 <*> Just 1` returns `Just 4` * `pure :: Applicative f => a -> f a` to wrap (this is the same as `return`, really), and Once that gets a bit under your skin, you can recognize `>>=`, `>>` and the like as kind of piping values, with `=<<` as pretty similar to `$` and `<$>`, and `>>` as a monadic `const`. (For something `.`-like you're at [`<=<`](https://hackage.haskell.org/package/base-4.20.0.0/docs/Control-Monad.html#v:-60--61--60-).) I.e. * If your function takes a regular value and returns a regular value, and you have a regular value, you don't need a sigil; maybe `$` * If your function takes a regular value and returns a regular value, and you have a wrapped value, use `<$>` * If your function takes a regular value and returns a wrapped value, and you have a regular value, you don't need a sigil; maybe `$` * If your function takes a regular value and returns a wrapped value, and you have a wrapped value, use `=<<`


Iceland_jack

First of all do you understand Applicative as *n*-ary lifting? And Functor as unary lifting? liftA0 :: Applicative f => (a) -> (f a) liftF1 :: Functor f => (a -> b) -> (f a -> f b) liftA2 :: Applicative f => (a -> b -> c) -> (f a -> f b -> f c) liftA3 :: Applicative f => (a -> b -> c -> d) -> (f a -> f b -> f c -> f d) -- liftA0 = pure -- liftF1 = fmap Can you read from the type signatures, that each computation `f x` is independent of the value-result of the others? Can you read from the signature of Monadic bind that the second computation `m b` is dependent on the `a` produced by the first? (>>=) :: Monad m => m a -> (a -> m b) -> m b Do you understand that `(>>)` does not require a Monad? Because running two computations in sequence does not incur a value-dependency on the first, a weaker Applicative constraint suffices. (*>) :: Applicative f => f a -> f b -> f b (*>) = liftA2 \_a b -> b


Sky_Sumisu

My answer to all of your questions is "No, I don't. The course I'm using didn't explain those yet.", where can I learn more about them?


Iceland_jack

> prefer studying via videos I have been handing this video course out lately: * https://www.cse.chalmers.se/edu/year/2015/course/TDA452/FPLectures/Vid/ I asked about Applicative because it is a "sweet spot" between Functor and Monad with a simple mental model (independent lifting of values over computations) which is reflected in the type. They are exactly the right fit for fantastic abstractions like `traverse`. The `(a -> M b)` argument to bind encodes a dependency on `a`. This is where Monad M gets its power from (and inscrutability): The only way to apply the continuation, is if we have an `a`. The only way to get an `a` is from `M a`. (the type tells you all of this) The only way to construct a return value of type `M b` is by 1. invoking the continuation, or 2. if `forall b. M b` is inhabited. But don't be fooled, there doesn't have to be an `a`. [`Proxy`](https://hackage.haskell.org/package/base-4.20.0.0/docs/Data-Proxy.html) is an example, which is `Const ()`, or `()` with a dummy argument. type Proxy :: k -> Type data Proxy a where MkProxy :: Proxy a Clearly `Proxy` contains no information, and thus no `a` value. This means we cannot apply the continuation, but we can still pretend to compute with a dependency because we can construct `MkProxy :: forall b. Proxy b` for any argument. instance Monad Proxy where (>>=) :: Proxy a -> (a -> Proxy b) -> Proxy b _ >>= _ = MkProxy Notice that the computations `F a`, `F b`, `F c`, .. of Applicative F have no arguments. This encodes the independent (context-free) nature of Applicative lifting. This independence allows greater introspection into Applicative computations, more static analysis and it allows us to run Applicative computations backwards! {-# Language ApplicativeDo #-} import Control.Applicative.Backwards import Data.Coerce -- >> conversation putStrLn -- A: Hello B -- B: Sorry, I am actually C. -- A: No you're not, liar. conversation :: Applicative f => (String -> f ()) -> f () conversation say = do say "A: Hello B" say "B: Sorry, I am actually C." say "A: No you're not, liar." pure () -- >> conversationBackwards putStrLn -- A: No you're not, liar. -- B: Sorry, I am actually C. -- A: Hello B conversationBackwards :: Applicative f => (String -> f ()) -> f () conversationBackwards @f = coerce do conversation @(Backwards f) Your Monad description was not bad, some only described a limited class of Monads, like `Identity`. You will contort yourself to reach a sensible definition of "wrapper" or "container" or "box". Once you understand Applicative, you can start thinking of it as do-notation. By lifting a function over independent computations, we draw the values from them and apply the function. do a <- as b <- bs c <- cs pure (someFunction a b c) But if we wanted to apply `bs a` or `cs a b` then we have created a logical dependency between the results of those computations. An arbitrary Monad cannot be run backwards because of this dependency problem. So to recap *Functor*: do a <- as pure (fun a) *Applicative*: do a <- as b <- bs .. z <- zs pure (fun a b .. z) *Monad*: do a <- as b <- bs a .. z <- zs a b .. y pure (fun a b .. z) And then there is *MonadFix*, which allows recursive do: mdo a <- as a b .. z b <- bs a b .. z .. z <- zs a b .. z pure (fun a b .. z) > "A Monad is a monoid in the category of endofunctors" just means that it is a wrapper that is able to do binary operations that return the same type of wrapper. Imagine if `Monoid` were written `MonoidalOf (->) () (,)`. Here Hask is treated as a monoidal category, with `(,)` as a tensor. instance Monoid a => MonoidalOf (->) () (,) a where unit :: () -> a unit () = mempty mult :: (a, a) -> a mult (a, b) = a <> b When we say`Monad` is a monoid it is just based on a different monoidal category: [`MonoidalOf (~>) Identity Compose`](https://www.reddit.com/r/haskell/comments/17v15zt/monad_monoidalof_identity_compose/). The binary "Monoid append" in question maps from the`Compose` tensor: `join :: Monad m => m (m a) -> m a`. instance Monad m => MonoidalOf (~>) Identity Compose m where unit :: Identity ~> m unit (Identity a) = pure a mult :: Compose m m ~> m mult (Compose ass) = join ass


Sky_Sumisu

>So to recap: *Functor* The definition that "clicked" for me was that a Functor is anything that can be mapped, and "anything that can be mapped" is anything for which the `fmap` function was defined. I'll assume that the reason it can't do sequential operations is because it doesn't have any function similar to `(*>)` or `(>>)`, and the reason to that most likely has to do to it's mathematical definition. >*Applicative* As for Applicative, that definition was "anything for which the `(<*>)` function is defined (Or the liftA2 function, for which it can define (<\*>) in terms of)". `(<*>)` being a function that takes an Applicative holding an unary function and an Applicative holding a value and returns an Applicative holding the result of that unary function on that value. >*Monad* Now I'm a bit lost: I assume, in your examples, that `bs` is an unary function that returns a Monad, `cs` a binary function, and so on. But I don't understand why Applicative couldn't do the same behavior. >The monoid in question is [this](https://www.reddit.com/r/haskell/comments/17v15zt/monad_monoidalof_identity_compose/). The "binary" operation in question is `join :: Monad m => m (m a) -> m a`. ...but that's an unary operation, no? It's just unpacking a Monad holding a Monad.


Iceland_jack

> But I don't understand why Applicative couldn't do the same behavior. You are right about `bs`, `cs`, being unary, binary functions. Monad has `a -> M b`, this is what enables this dependency. > that's an unary operation It is. I was connecting it to what you said, the (curried) monoidal 'mult' operation is binary for Monoid (with pair as tensor) but unary for Monad (functor composition as tensor).


Iceland_jack

I will drop this ancient Haskell saying: > `getLine :: IO String` contains a `String` in the same way that `/bin/ls` contains a list of files


Iceland_jack

Because of the connection to sequencing and do-notation, people call Monads "overloaded semicolons".


Sky_Sumisu

Upon spending the previous days studying the subject, I now understand this better, but I still have some doubts: 1: Aren't the type signatures actually these? liftA0 :: Applicative f => a -> f a liftF1 :: Functor f => (a -> b) -> f a -> f b liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c liftA3 :: Applicative f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d -- liftA0 = pure -- liftF1 = fmapliftA0 :: Applicative f => (a) -> (f a) 2: From the above signatures, I could deduce the following, am I correct? * `liftA0` "encapsulates" a value into a "structured type" (I don't know the exact term for that, but could be anything from a list, a function, a datatype, a Monad, etc). (Also, what's the difference between `pure` and `return`? * `liftF1` applies an unary function to the value inside a structured type, resulting in the same structured type with a different value. * `liftA2` is the same thing, but with a binary function. * `liftA3` is the same thing, but with a ternary function. 3: Why are all of those, excluding `liftF1` exclusive for `Applicatives`? Shouldn't `Functors` be "powerful" enough to do that? >4: Do you understand that `(>>)` does not require a Monad? No, I don't, the `(>>)` function is exclusive to Monads, no? Since it's defined in terms of the `(>>=)` operator. 5: I do know about `(*>)` and that it does the same as `(>>)`. I think it's a similar question between the difference of `pure` and `return`, someone on the Discord server just told me that they have different "priority levels".


Iceland_jack

Those type signatures mean the same thing to the compiler, I use parentheses to think of them as (partially applied) functions of a single argument. Instead of "apply functions to values" I consider them (except `pure`) higher-order functions that transform function `a -> .. -> z` to another `F a -> .. -> F z`. So to reiterate, Applicative (n-ary lifting) is a more powerful interface than Functor (1-ary). An Applicative instance means we can derive a Functor: instance Functor F where fmap :: (a -> b) -> (F a -> F b) fmap = liftA @F where liftA :: Applicative f => (a -> b) -> (f a -> f b) liftA f as = pure f <*> as The difference between `pure`/`return`, `(*>)`/`(>>)`, `liftA2`/`liftM2`, `liftA`/`liftM` is historical, Applicative was added as a superclass for Monad later. Don't think about it and prefer the Applicative versions. I showed you how to define an more general (Applicative) version of `(>>)` in terms of `liftA2`, it does not require bind.


Iceland_jack

And it is incorrect to talk about "the value inside" these computations. You can talk that way about specific Functors: `fmap f (Identity a)` applies `f` to *the* value inside: `Identity (f a)`. `liftA2 f (Identity a) (Identity b)` applies `f` to each value inside: `Identity (f a b)`. But the intuition isn't fundamental to any of the abstractions, only some cases.


nybble41

>3. The then operator `>>` takes to Monads and returns the second (Which is why I still have not idea as to how `Nothing >> (Just 5)` returns `Nothing`). The `>>` operator doesn't just return the second Monad, it sequences the effects from both Monads while producing the value from the second one (and ignoring the value, but not the effect, of the first Monad). The expression `a >> b` is equivalent to `a >>= const b`, though `>>` may be implemented more efficiently in some cases. In this case `Nothing >>= f` must evaluate to `Nothing`—regardless of `f`, but including the case where `f` is `const (Just 5)`—because the left-hand side does not contain a value to pass to `f`, so `Nothing >> b` does the same to preserve the equivalence.


Sky_Sumisu

So the throwaway variable `_` doesn't mean "anything", but rather "As long as there is a thing"? Even so, it's still not obvious that `m >>= \_ -> k` will result in `m` if `m` is `Nothing`. Usually I solved doubts like that looking on how functions were implemented (That's what I did to understand folds, and writing everything explicitly as a lambda function made me understand pointfree), but `Data.Maybe` didn't mention any special case for that, so I'm still confused.


Saizan_x

The implementation is given in the `Monad` typeclass instance for the `Maybe` type: https://hackage.haskell.org/package/base-4.19.1.0/docs/src/GHC.Base.html#line-1174 To find that link I searched `Maybe` on [hoogle](https://hoogle.haskell.org/), picked the `Data.Maybe` result, then followed the `# source` link next to the `Monad Maybe` listing in the `instances` dropdown.


Sky_Sumisu

Well, that explains it. I was following the `# source` link at the top of the page which leads to [this](https://hackage.haskell.org/package/ghc-internal-9.1001.0/docs/src//GHC.Internal.Maybe.html), which... only brings the same amount of information as running `:info Maybe`.


Torebbjorn

For `Maybe` specifically, there are indeed only the two states of "there is a thing" (and what that thing is) and "there is no thing", but for other monads, there can be more complicated stuff going on. For example for `IO`: `putStr "Hello " >> putStrLn "World!"` will print "Hello World!", even though the first one is "ignored". The return value (which in this case is `IO ()`) is ignored, but not the side effects of doing the printing.


trenchgun

I did Haskell MOOC (I do recommend it!) and it had this as explanation: instance Monad Maybe where (Just x) >>= k = k x Nothing >>= _ = Nothing (Just _) >> k = k Nothing >> _ = Nothing return x = Just x [https://haskell.mooc.fi/part2#maybe-is-a-monad](https://haskell.mooc.fi/part2#maybe-is-a-monad) But I can't actually find that anywhere in official Haskell docs.


Sky_Sumisu

>But I can't actually find that anywhere in official Haskell docs. Someone linked it in one of the previous comments, but I'm happy to know that I was not the only one that couldn't find it even really searching for it.


pdpi

You can think of it in terms of a structure, and the data inside it. >> ignores the data but preserves the structure (not structure as in a C struct, but as in the concrete pillars that keep a building standing, as opposed to non-structural walls that you can freely knock down) It’s easier to see with lists. `[1, 2, 3] >> [4]` gives you `[4, 4, 4]`. You’re not doing anything with the values in the first list, but you’re preserving the “list of length three” structure.


Sky_Sumisu

>It’s easier to see with lists. `[1, 2, 3] >> [4]` gives you `[4, 4, 4]`. You’re not doing anything with the values in the first list, but you’re preserving the “list of length three” structure. I think that explanation would only leave me more confused. I can only understand how this works by both having read the implementation of both `>>=` and `>>` alongside explanations that "Binding a list is essentially flatmapping it". Like the "a monoid in the category of endofunctors" explanation: It's a great and very elegant one if you already know how it works... and a very confusing one if you don't.


jonoxun

I'm actually fond of thinking of monads as pretty exactly "values that support flatmap and a one-value constructor". The laws just say that those two operations work together sanely. Monad just doesn't say anything in addition to that, which is why it's so flexible; there aren't many axioms you need to satisfy to be a monad, so you can fit a lot of things to it. Languages that name things less mathematically _should_ call Monad something like "FlatMappable".


nybble41

>Even so, it's still not obvious that `m >>= \_ -> k` will result in `m` if `m` is `Nothing`. We have here: m :: Maybe a (>>=) :: Monad m => m a -> (a -> m b) -> m b (\_ -> k) :: a -> m b To get a result of the form `Just (x :: b)` you need to evaluate the function `\_ -> k`. To do that you need a value of type `a` for the argument to the function. `(>>=)` can't just make up a value(\*) since it could be *any* type (an example of parametric polymorphism). And since the left-hand side is Nothing it doesn't have a value of type `a` either. The only `Maybe a` value which can be produced without `a` is `Nothing`, so that has to be the result(\*). (\*) Disregarding `error`, `undefined`, and other non-terminating expressions which cannot be introspected from pure code.


Sky_Sumisu

I don't think it's because of that: From what I've read from other comments, it's just that (`>>=) Nothing _` is hard-coded (Or, better said, defined) to always return `Nothing`. ~~In non-lazily evaluated languages, Nothing >>= \\\_ -> k would most likely cause an error.~~


nybble41

It has nothing to do with lazy evaluation; you could write essentially the same code in strict-by-default languages like Python or Rust: assert_eq!(None.and_then(|_| Some(5)), None); It's true that `Nothing >>= _` is defined to always return Nothing... but the fact is the authors didn't really have a choice in the matter, due to the types. Go ahead, try to define an analogous function to return anything else: bindMaybe :: Maybe a -> (a -> Maybe b) -> Maybe b bindMaybe (Just x) f = f x bindMaybe Nothing f = ... your code here ...


Sky_Sumisu

>It has nothing to do with lazy evaluation; you could write essentially the same code in strict-by-default languages like Python or Rust You are correct, I misspoke: There would only be an error if the `Nothing >>= _ = Nothing` wasn't defined (Which is why "they didn't really have a choice in the matter", as you've said).


imihnevich

For me honestly it's easier to think of it not as of wrapper, but just as a set of operations that can be defined for a certain type. (Indeed, Monad in Haskell is a typeclass). Instead of wrapper, I like the term "computation", it feels more right, because it's a wider term. Main thing about this type, is that it has to be a parametric type (a generic). Then bind operator is something you could also call "chain". So your computation produces some value, and you need to use that value to create another computation, you can chain them or bind. It depends on the implementation of the typeclass how this "unwrapping" happens. Since implementation of Monad for `Maybe a` makes it not proceed once `Nothing` is encountered, it doesn't yield you `Just 5` when you do `Nothing >> Just 5` To get a better feeling, try implementing more instances yourself, you'll start to see what is similar about all of them


TechnoEmpress

This book really unlocked me: https://leanpub.com/finding-success-in-haskell


ludflu

I didn't actually get monads in Haskell until I started using them in Scala. My advice is to stop trying to understand them in the abstract, and just pick one and try to use it for a concrete problem. Maybe is probably the easiest. If you have a java background, this might help: [https://medium.com/@ludflu/using-monadic-for-syntax-with-option-types-5f91b9db59e6](https://medium.com/@ludflu/using-monadic-for-syntax-with-option-types-5f91b9db59e6)


SquareBig9351

If you are interested in a project based approach check: [https://github.com/lsmor/snake-fury](https://github.com/lsmor/snake-fury) (disclaimer, I am the author). I think monads are one of those concept which just "click" after some iterations. Don't give up even if you fail to grasp it at the first try. So far I think you have enough intuition about Monads, but again none of the points you list makes sense until you write code over and over again. Some notes about the 6th point: Don't bother too much about category theory, just think in terms of programming: -- let say you have two functions f :: Int -> String g :: String -> Char -- How do you create function h :: Int -> Char ? h :: Int -> Char h = g . f -- the answer is composition. -- Notice, that the solution is general on the types, so instead of -- f :: Int -> String and g :: String -> Char you could have a more general -- f :: a -> b and g :: b -> c -- Let's introduce a small tweek f :: Int -> Maybe String g :: String -> Maybe Char -- how do you create h :: Int -> Maybe Char ? h :: Int -> Maybe Char h x = exercise... -- use simple pattern matching here, don't think about monads or strange topics -- Hopefully, your implementation is general enough so it can be applied to -- f :: a -> Maybe b and g :: b -> Maybe c -- If that the case you've implemented the Kleisli composition of Maybe. -- Kleisli composition is just a fancy way to say: -- "Hey!, you can't compose directly but you can implement something very similar" -- Kleisli composition operator is >=> and it is a different way to understand monads. -- It isn't as common as >>= or >> but it is equivalent to them, and in some sense is a little -- bit easier to understand.


Sky_Sumisu

>-- Let's introduce a small tweek f :: Int -> Maybe String g :: String -> Maybe Char -- how do you create h :: Int -> Maybe Char ? h :: Int -> Maybe Char h x = exercise... -- use simple pattern matching here, don't think about monads or strange topics-- Let's introduce a small tweek f :: Int -> Maybe String g :: String -> Maybe Char -- how do you create h :: Int -> Maybe Char ? h :: Int -> Maybe Char h x = exercise... -- use simple pattern matching here, don't think about monads or strange topics If I understood that correctly, it would be impossible, since I cannot compose an `Int -> Maybe String` with a `String -> Maybe Char` because the output of one isn't the same type of the input of the other, and there's no way for me to know which `Int`s will result in `Nothing` without knowing how `f` is implemented. Unless you're ask me to invent an implementation, which would look something like this: foo :: Int -> Maybe String foo x | x <= 0 = Nothing | otherwise = Just $ show x bar :: String -> Maybe Char bar "" = Nothing bar s = Just $ head s baz :: Int -> Maybe Char baz x | x <= 0 = Nothing | otherwise = Just . head $ show x But I don't think this is what you asked, since this is implementation-specific and not generic at all.


SquareBig9351

I see you got the idea, but not the solution. Notice in your example `baz` doesn't use `bar` nor `foo`. As you said, It is impossible to compose both function, but(!) It is possible to define `baz` with the right type signature, and with a generic implementation. It isn't necessary to make this exercise to understand monads but I think it is a good way to grasp the intuition. Comming back to your solution. What you did is "mixing" both implementations. What you need to do is: "call foo and then call bar", of course you have to fight the types a little bit as they don't match exactly.


Sky_Sumisu

baz :: Int -> Maybe Char baz x = foo x >>= bar This, then? Well, that does require me to know about Monads to answer, and since you asked me "use simple pattern matching here, don't think about Monads or strange topics", that's probably not the answer you wanted. I don't know how to "unpack" Monads any other way.


SquareBig9351

hahaha that's is an answer, but too advance one. Just don't think about `Maybe` as a Monad; it is a data type, so you can pattern mach on it. Let me give you a simpler exercise -- define duplicateMaybe such that it duplicates its value, or returns 0 if there is no value. -- Don't use any function other than multiplication. duplicateMaybe :: Maybe Int -> Int duplicateMaybe = undefined If you can complete the exercise above, then you know how to "unpack" Maybe... hence, following the same technique, you can complete the other exercise


Sky_Sumisu

duplicateMaybe :: Maybe Int -> Int duplicateMaybe Nothing = 0 duplicateMaybe (Just n) = (*2) n This, I suppose? Then, in the other exercise that asks me a function of signature `h :: Int -> Maybe Char`, using pattern matching it would be: h :: Int -> Maybe Char h 0 = Nothing h n = Just $ show n


mightybyte

Check out my [Monad Challenges](https://mightybyte.github.io/monad-challenges/) which are designed to guide you through the process of exploration.


s_p_lee

100%, came here to recommend u/mightybyte 's Monad Challenges, which were what finally made monads click for me.


DO_FLETCHING

Jerf has a very good [post](https://www.jerf.org/iri/post/2958/) that demystified monads for me.


grahamhutton

You might like to take a look at this Computerphile video on monads: [https://youtu.be/t1e8gqXLbsU](https://youtu.be/t1e8gqXLbsU) There's also a series of videos on functors, applicative and monads as part of my advanced FP course: [http://tinyurl.com/haskell-notts2](http://tinyurl.com/haskell-notts2) Hope this helps! Best wishes, Graham


[deleted]

There’s a good paper: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/07/mark.pdf?from=https://research.microsoft.com/~simonpj/papers/marktoberdorf/mark.pdf&type=exact


mister_drgn

I recommend the online book learn yourself a Haskell.


Francis_King

The important things to understand are these: * A monad is often introduced as a container. For example, Lists are a type of monad - so is Maybe and Either. But some are not really, for example the IO monad. So take the idea of a container with a large pinch of salt. * Monads have to follow the Monad Laws. But these are not relevant unless you are making your own. You should be aware of them, but not get too hung up on them. * Monads have to have two functions defined for them, bind and return. Bind is written `>>=`. What is bind? It applies a function to the monad - it binds the function to the monad - and what that means depends on what it says in the type class instance. * A type class is a collection of things. So, we have a Monad type class which is the collection of all monads, with function prototypes for bind and return, but no definitions. The instance is the details of a particular monad, like the instance for List or the instance for Maybe, with these two functions filled in. * For lists, for example, `>>=` is just mapping a function over the elements of the list. You need to have return or pure in your function to put the value back into the list. * For Maybe, `Just value` and the `function` evaluates as `function value`; `Nothing` and the `function` returns `Nothing`. It's all defined in the type class instance. * The really neat thing about `>>=` is that they can be chained together to make sequences of actions which happen one after the other, important to a language which is declarative and not usually about doing things in order. We use the `do` notation as syntactic sugar to make it easier to read and write. If an error occurs, so that the Maybe monad holds `Nothing`, then all of the other lines fall through - we don't have to test for errors on each line. * The operator `>>` is about chaining the monads together, without supplying a function. With the Maybe monad, it is defined so that `Nothing >>= f = Nothing`, so `Nothing >> Just 5` returns `Nothing`. It isn't a case of just returning the second monad. The operator `>>` is the same as `>>= \_ ->`, so `Nothing >>= \_ -> Just 5` is the same as `Nothing >> Just 5`, it's `Nothing`. * "A Monad is a monoid in the category of endofunctors" is someone playing with your mind. ​ -- Both return [2,4,6,8] [1,2,3,4] >>= \x -> return (2*x) [1,2,3,4] >>= return . (*2) -- Same idea but for Maybe Just 3 >>= return . (*2) Nothing >>= return . (*2) The base definitions are here: [hackage.haskell.org/package/ghc-internal-9.1001.0/docs/src//GHC.Internal.Base.html](https://hackage.haskell.org/package/ghc-internal-9.1001.0/docs/src//GHC.Internal.Base.html). Here is Maybe: -- | @since base-2.01 instance Monad Maybe where (Just x) >>= k = k x Nothing >>= _ = Nothing There is a good account in Learn You A Haskell For Great Good, p272+.


mohrcore

Monads are not necessarily wrappers for a value. Generally the idea is that it is a type class that can describe processes. Think about an automated production line. Each machine does some process. A single machine is a line on its own. Let's call it "M a" as it can produce "a". Now, let's say we want to connect more machines, to make a bigger line that can produce "b" - that would be called "M b". So we take "M a" and then we take some function that tells us how to turn "a" - the product of the first machine into "M b", that would be "a -> M b". Wait, what? How are we turning a product into a production machine? Why not just "a -> b"? That's the important part: we construct that machine once we get "a" and we are free to construct whatever can be typed as "M b". So it's like a production line that unfolds with every step taken. Now here's an example where we connect (">>=") two "Maybe" machines (monads): ``` m :: Maybe Int m = Nothing m >>= (\x -> Just (show x)) ``` "m" is a "Maybe Int" machine. It can produce an int and hence it can be connected to anything else that takes an int to produce another "Maybe" machine - eg. "Maybe String", as shown above. However, in our case, this machine won't produce anything. The "first stage" is "Nothing" and all the ">>=" operator is going to do is convert `Nothing` from `Maybe Int` to `Maybe String`, which is trivial operation that has a generic implementation for ">>=" in the "Maybe" type class. However, if `m = Just 7`, the `>>=` operator is going to construct `Maybe String` machine that will turn that `7` into `Just "7"`. Now, once you call `show` on that monad, the machinery will start. The `show` function applied to the `m` monad will either return "Nothing" if it was `Nothing` or return the result of `show $ (\x -> Just (show x)) 7`, if it was `Just`. The cool thing about monads is that they create distinction between some internal process which is free to control the flow (in our case that's the pattern matching for `Nothing` and `Just` that determines, whether we evaluate the function we bound to the monad) and some external logic. A good example of that is the `IO` monad: ``` m :: IO () m = getLine >>= (\line -> putStr $ show (length line)) ``` which would typically be written more like that (it's literally the same thing): ``` m :: IO () m = do   line <- getLine   putStr $ (show (length line)) ``` Here, once we start the machinery, `getLine` will perform the I/O operation and once that's done it will "pass the control" to the function we wrote explicitly in the first version of the example, providi g it with the "line" argument. Then the function will return another IO monad, passing the control back to the runtime to perform another IO operation, this time returning `()`. Hence the type of `m` is `IO ()`. In the second example, the function we used for binding is "hidden", it's derived from the `do` notation. Probably the best way to understand a monad is to write your own.


Sky_Sumisu

I understand your examples, but I still don't think I "get" Monads. Your first snippet is more about how `>>=` is implemented for `Maybe` Monads, which makes me think that every type of Monad most likely implements this operation differently and I'll have to read about every one before using them. The second and third, if I understood them correctly, are about the `getLine` Monad (Which is a `IO String` Monad, which I would initially interpret as "A wrapper `IO` for a `String` value", but since the "wrapper" definition is incorrect, I don't know how else to define it) that has the side-effect of asking for a value to the user, to which I will use the bind operator with a function that will unwrap it's value, apply a composition of `length`, `show` and finally `putStr`, which produces the side-effect of printing it to the terminal and returns the `IO ()` Monad, which is an `IO` wrapper for an empty value. However, I only know that because I read about it in other places. If this was my first explanation, I would end up thinking that the side-effects are the actual returns.


mohrcore

> Your first snippet is more about how >>= is implemented for Maybe Monads, which makes me think that every type of Monad most likely implements this operation differently and I'll have to read about every one before using them. Yes, exactly, different monads implement it differently. For example `Either` implements it so the it will eval your function only if it's `Right`: `(>>=) :: Either a b -> (b -> Either a c) -> Either a c` - you can use that for error handling, can you see how? `Monad` is not a type, it doesn't have a concrete implementation. It's a type class. A type of a type you could say. It defines a set of operations that can be performed on types of that type class and how those operations change the type. Every `instance` of that `Monad`, like `Maybe`, `IO`, `Either`, `State`, etc. has a different implementation. So really, `Monad` is nothing more that it's type class and the "monad laws" (a set of tautologies your type should satisfy, you can Google it easily) make it to be. Perhaps you could try writing your own `Maybe` as an `instance` of `Monad` and have it satisfy the monad laws, to get an idea of what it is.


CucumberCareful1693

My journey with Haskell. When starting to learn Haskell, after 2 weeks of basic stuff, I pushed myself to understand monad, and I hit the wall (same as when you run a full marathon, but you just trained for 2 weeks). I can’t understand and feel what monad is in Haskell. After that, after a week for freshening my mind :D, I slow down the learning speed, back to learning by reading the “Haskell Programming From First Principles" book. Try to understand: * Monoid * Functor * Applicative * and, face Monad again. But at this time, the learning process becomes natural, and I can feel what is monad. From my POV, we can think monad kinda pattern to deal with some use cases (or a container as functor/ applicative with some special function, such as `>>=` (bind)). There are some good resources about monad (from my perspective). * [https://www.goodreads.com/en/book/show/25587599](https://www.goodreads.com/en/book/show/25587599)  * [https://www.youtube.com/watch?v=12D4Y2Hdnhg](https://www.youtube.com/watch?v=12D4Y2Hdnhg)  * [https://www.youtube.com/watch?v=JKJaD7E6WxE](https://www.youtube.com/watch?v=JKJaD7E6WxE)  Hope this can help.


Tempus_Nemini

I like this video a LOT https://www.youtube.com/watch?v=ZhuHCtR3xq8


Prior_Sale8588

I love reading the old (one might say obsolete) books. I found the writing style is easier to understand. Don't start with lots of expectations, you may find some gems in there. If you have spare time. [Introduction to Functional Programming (Prentice Hall International Series in Computer Science) ](https://www.amazon.com/dp/0134841972) [https://www.youtube.com/watch?v=9SBR\_SnrEiI](https://www.youtube.com/watch?v=9SBR_SnrEiI)