4 ms·
return isn't syntax, it's a normal function of type Monad m => a -> m a. The "sniffing" that you are talking about is that overloading is done on the return typ
by gsg 9y ago
return isn't syntax, it's a normal function of type Monad m => a -> m a. The "sniffing" that you are talking about is that overloading is done on the return type.
Why does it exist at all? Speaking loosely, monads are about composing functions that look like a -> m b. Here's regular composition alongside the 'monadic' one:
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> (a -> m c)
As you can see, the same except for the m wrapping each function's results. Just like normal function composition, there is an identity element - that's what return is. Again, a comparison:
id :: a -> a
return :: Monad m => a -> m a
Again, the same except for the m wrapping the result. Both composition operators are associative, and both have the same relationship with their identity operation:
id . f = f return <=< f = f
f . id = f f <=< return = f
(That's why there are monad laws, to ensure those properties hold.)
So return is very straightforward: it is the identity of functions that return monads. It's unfortunate that both the name and the presentation of monads in Haskell tend to obscure this.
- lacampbell 9y agoI think what's confusing me here is haskells type classes, which I've never found intuitive (despite having "learned" them 3 or 4 times already..). The definition of return still baffles me, in the absence of some kind of module or object on its left hand side, I can't make sense of how it "knows" how to overload. I'm probably better of learning monads in the context of a language I'm more familiar with, like ocaml. I appreciate the effort though.
- gsg 9y agoVery understandable, type classes + inference + monads + do notation is quite a stack of unfamiliar machinery to understand all at once. The return type is inferred, and the type is what the type class machinery is driven by. You can get some more visibility into that by playing in ghci: return 0 :: [Int] => [0] return 0 :: Maybe Int => Just 0 Having behaviour driven by return type takes a bit of getting used to.
- moomin 9y agoReturn value polymorphism is hugely powerful though: it means you can write stuff that works for any Monad (involving return). Without it you can't sensibly do that.
- dllthomas 9y agoSure you can. It just involves a little more manual plumbing. Certainly less convenient, but not actually as bad as all that in the typical case.
- dllthomas 9y agoIn the absence of some kind of module or object on its left hand side, return has a polymorphic type. e.g. return 'c' :: Monad m => m Char You can actually sort of think of this as a function from typeclass dictionary to value, except the compiler will pass that dictionary itself once it's inferred what it should be (and will then inline/optimize it away, where it can).
- BoiledCabbage 9y agoA typeclass is really nothing but a basic java/c# interface. The 4 things you do with an interface are: 1. Declare an interface 2. Describe the contract of the interface 3. Declare that a datatype (or class) adheres to that interface 4. Provide an implementation of the the contract of the interface (fulfill the contract). A haskell Typeclass does exactly that. The keyword "class" is where you do #s 1 & 2. The keyword "instance" is where you do #'s 3 & 4. The only notable difference is: If an ISizable has int GetSize() method in haskell instead of the contract being int ISizable.GetSize(), it is static int GetSize(ISizable x). Or in Haskell: instance ISizable MyType where GetSize :: ISizable -> Int -- Note you don't actually type this line GetSize x = ...