The lessons behind “id :: a -> a”
The haskell id function is most mysterious to me when i first started with Haskell because its a function that is most easily overlooked. The type signature of this function is
id :: a -> a
and what it says is “id returns whatever it took” and initially i was like “Huh?”. One of the uses can be found in GHC.Base.hs file (if you were browsing the GHC codebase like i was) which is listed in the join function’s definition:
join :: (Monad m) => m (m a) -> m a
join x = x >>= idWhat is cool about this seemingly innocent function is that join uses id to simply return the innermost layer of abstraction.
join :: (Monad m) => m (m a) -> m a
join = do { xx <- x; xx }
-- this is effectively the same as the above.Considering that join peels away one layer of abstraction, when i compose 2 join s together, i would be able to peel away 2 layers of abstraction and so on so forth. Funny enough that all this power came from id . Just to illustrate why this is possibly the case, let’s go over a simple example:
> join [[1],[2,3]]
> [1,2,3]
nothing extra ordinarily wrong is going on, everything's expected.Contrast the above with this
> join2 x = do { xx <- x; return x }
> join2 [[1],[2,3]]
-- What is going on?The main thing you should realise is the difference between abstaining the use of return :: Monad m => a -> m a because it wraps the value and in the situation where everyone knows what join is suppose to do, it would be wrong to use the definition of join2. The semantics of the function we want to write definitely would guide us in knowing whether the function conforms to the desired outcomes we want and the laws of Monads are there to guide us in writing the proper monadic function. How so? Well, the first two laws of Monads (left-identity and right-identity) shows us how to avoid any unnecessary use of return and the last law (i.e. associativity) tells us whether our function can be broken down further and composed together. These 3 monad laws are very important from the perspective of a software engineer since they help us build maintainable and reusable software.
