3 ms·
You may already be aware of this, but for those who aren't: `return` isn't actually part of do-notation syntax, it's a function name. It's true that do-notation
by chriswarbo 12y ago
You may already be aware of this, but for those who aren't: `return` isn't actually part of do-notation syntax, it's a function name. It's true that do-notation must result in a monadic value, but that's just because of the type. `return` can be used to construct that monadic value, but there are many other ways to do so:
func1 :: Maybe Int
func1 = do x <- foo
y <- bar
return (x + y) -- Using return
func2 :: Maybe Int
func2 = do x <- foo
y <- bar
Just (x + y) -- Building a monadic value explicitly
func3 :: Maybe Int
func3 = do x <- foo
y <- bar
plusJust x y -- Using some other function
plusJust :: Int -> Int -> Maybe Int
plusJust x y = Just (x + y)
Also, since `return` is a function, we can use it outside do-notation:
wrapAndApply :: a -> (a -> b) -> [b]
wrapAndApply x f = fmap f (return x)
What makes `return` "special" is that it's a method of the `Monad` typeclass. In other words, the name `return` is overloaded to work with any instance of `Monad` (`IO`, `Maybe`, `List`, etc.), depending on the type that's required of it.
Loads of other functions are overloaded like this, eg. `+` has implementations for `Int`, `Float`, etc. so it's not monad-specific.
The part which is monad-specific is that Haskell's do-notation is hard-coded to the built-in Monad typeclass. We're completely free to make our own monad implementation, separate to Haskell's built-in one, but we won't be able to use do-notation with them unless we implement the built-in `Monad` typeclass as well. That could be as simple as mapping one name to the other:
instance MyMonad a => Monad a
return = myReturn
(>>=) = myBind
- dllthomas 12y ago"The part which is monad-specific is that Haskell's do-notation is hard-coded to the built-in Monad typeclass." That's not quite true, at least in GHC. It's hard-coded to use (>>=) and fail, but the only thing that prevents you from defining your own is the name collision. With -XNoImplicitPrelude, you can (and they can even be locally scoped - I did some cute things with this once that I'd never want to see in production code...).