I can't understand the difference between Dot (function composition) and bind (>>=) .
If I understand, these two ways take the previous result of a function for a new function.
So what is the difference ?
I can't understand the difference between Dot (function composition) and bind (>>=) .
If I understand, these two ways take the previous result of a function for a new function.
So what is the difference ?
They are pretty different. Let's look at their signatures:
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
As you said, the function composition is just a way to pass a result of one function as an argument to another one like this:
f = g . h
is equivalent to
f x = g (h x)
You can think about is as some kind of a "conveyor", where your value goes through several processing steps.
But (>>=)
is quite different. It is related to such context as monad which is something like some value in some context (it's highly recommended to read the previous link if you aren't familiar with it).
So let x
be some value in a context. Our context will be nullability (Maybe
monad), and the value is 2
. So, x = Just 2
. We could, for example, get it as a result of a lookup from some associative container (such operation might fail, that's the reason why it is Maybe Int
, but not Int
).
Now we want to pass our x
to some arithmetic function f
that accepts just Int
and may fail, so its signature looks like:
f :: Int -> Maybe Int
We can't just pass our value because of type mismatch. We could unpack x
and handle some cases with if
, but we could do that in almost all other languages. In haskell, we can use (>>=)
:
x >>= f
This allows as to chain the effects:
x
is Nothing
, then the result is Nothing
immediatelyx
is unpacked and passed to f
This is a generalization of the operator ?.
, that you could see in some languages:
x = a?.func1()?.func2();
which checks for null
at each "step" and stops immediately if hits null
or returns the value in case of success. In haskell it looks like:
x = a >>= func1 >>= func2
However, bind with monads is a much more powerful concept, allowing you, for example, to emulate stateful computations in a language without mutability like haskell.
(>>=)
is a form of function application.
(>>=) :: Monad m => m a -> (a -> m b) -> m b
flip ($) :: a -> (a -> b) -> b
It takes a value, but "extracts" part of it in order to apply the given function. Chaining two functions, like x >>= f >>= g
requires the argument type of g
to be different from (but at the same type similar to) the return type of f
, unlike composition, which requires the types to match exactly.
Composed with return
, it
really is just function application, but restricted to certain kinds of functions.
flip ($) :: a -> (a -> b) -> b
(>>=) . return :: Monad m => a -> (a -> m b) -> m b
(.)
is more like (<=<)
(from Control.Monad
).
(.) :: (b -> c) -> (a -> b) -> a -> c
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
But again, instead of simply passing the result of one function to another, it first "extracts" a value before doing application.