REVISED: Thursday, February 8, 2024
Haskell code shows copious amounts of (>>=) pronounced bind.
A Monad is a data structure which implements a Monad type class and satisfies Monad laws. A Monad typeclass defines two functions, the (>>=) and the return that know how to unwrap and wrap data. (>>=) bind is used to unwrap data and apply it to a function which takes the data as input and outputs a monad. (>>=) binds the unwrapped result of the computation on the left to the parameter of the one on the right. return is used to wrap data into a monad's type constructor.
Unwrap is the deconstructor in Haskell; destructing/unwrapping. Wrap is the constructor in Haskell; constructing/wrapping. You can also think of IO as a wrapper. The unwrapping of >>= cancels out the wrapping done by return, leaving only the function.
A Monad is a data structure which implements a Monad type class and satisfies Monad laws. A Monad typeclass defines two functions, the (>>=) and the return that know how to unwrap and wrap data. (>>=) bind is used to unwrap data and apply it to a function which takes the data as input and outputs a monad. (>>=) binds the unwrapped result of the computation on the left to the parameter of the one on the right. return is used to wrap data into a monad's type constructor.
Unwrap is the deconstructor in Haskell; destructing/unwrapping. Wrap is the constructor in Haskell; constructing/wrapping. You can also think of IO as a wrapper. The unwrapping of >>= cancels out the wrapping done by return, leaving only the function.
1. HASKELL WRAP UNWRAP EXAMPLE 1
The identity monad is a monad that does nothing special.
"Copy Paste" the following example into your text editor and "File Save As" WrapUnwrap.hs to your working directory.
import Prelude hiding (Maybe(..))
import Control.Monad
import Control.Applicative
import Control.Applicative
instance Functor Wrap where
fmap f (Wrap a) = Wrap (f a)
fmap _ Nothing = Nothing
instance Monad Wrap where
return a = Wrap a
Wrap a >>= f = f a
instance Applicative Wrap where
pure = Wrap
Wrap f <*> Wrap a = Wrap (f a)
_ <*> _ = Nothing
f :: Num a => a -> Wrap a
f a = Wrap (a + 1) -- Returns an incremented wrapped result.
f a = Wrap (a + 1) -- Returns an incremented wrapped result.
(>>=) f (Wrap a) = f a -- unwrap does the exact opposite of wrap.
Load the example into GHCi.
Prelude> :load WrapUnwrap
[1 of 1] Compiling WrapUnwrap ( WrapUnwrap.hs, interpreted )
Ok, modules loaded: WrapUnwrap.
Prelude>
As shown below we can take data and wrap it inside a data type and then increment it while it is wrapped in that data type:
Prelude> f 2
Wrap 3
Prelude>
2. HASKELL UNWRAP WRAP EXAMPLE 2
Consider the following Functor:
class Functor f where
fmap :: (a -> b) -> f a -> f b
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just x) = Just (f x)
If a value is wrapped in Just the fmap calls the function on the unwrapped value, and then rewraps it in Just.
3. HASKELL WRAP EXAMPLE 3
Wrap was easy to see in Example 1. You have to look closer to see wrap in Example 2.
"Copy Paste" the following example into your text editor and "File Save As" JustNothing.hs to your working directory.
module JustNothing where
import Prelude hiding (Maybe(..), lookup)
data Maybe a = Just a | Nothing
deriving (Eq, Ord, Show)
pie :: [(String, String)]
pie = [("3.141592653589793", "pi")]
lookup key [] = Nothing
lookup key ((k, v) : rest) = if key == k then Just v else lookup key rest
main = do
putStrLn "Please type pi to 15 decimal places then press Enter."
word <- getLine -- Notice getLine has type "getLine :: IO String", <- is used to unwrap String from the IO action and bind it to word.
print (lookup word pie) -- Notice word has type "word :: String", not IO String; therefore, word is not an IO action.
if word == "3.141592653589793"
then return ( "Congratulations!" )
else main
Load the example into GHCi:
Prelude> :load JustNothing
[1 of 1] Compiling JustNothing ( JustNothing.hs, interpreted )
Ok, modules loaded: JustNothing.
Prelude>
Run the example in GHCi:
Prelude> main
Please type pi to 15 decimal places then press Enter.
3.141592653589793
Just "pi"
"Congratulations!"
Prelude>
4. SUMMARY
The Haskell programming language is a functional language that makes heavy use of monads. A monad consists of a type constructor M and two operations, bind >>= and return. The return operation takes a value from a plain type and puts it into a monadic container using the constructor. The bind >>= operation performs the reverse process, extracting the original value from the container and passing it to the associated next function in the pipeline. This process effectively creates an action that chooses the next action based on the results of previous actions. Therefore, we should be able to determine our next action based on the results of previous actions. In other words, if x is a computation, and f is a function x >>= f is a computation which runs x, then applies f to its result, getting a computation which it then runs. Monads in Haskell can be thought of as composable computation descriptions.
Using return and bind we can wrap data and manipulate the wrapped data while keeping that data wrapped. We can also chain functions together that wrap. And in the process of doing these things we learn how monads work.
The unwrap wrap analogy is used to help you acquire intuition regarding how monads work. However, do not take unwrap wrap too literally. Unwrap wrap are mental tools to help you eventually gain the insight needed to think of monads in a computational context not in a unwrap wrap context.
The unwrap wrap analogy is used to help you acquire intuition regarding how monads work. However, do not take unwrap wrap too literally. Unwrap wrap are mental tools to help you eventually gain the insight needed to think of monads in a computational context not in a unwrap wrap context.
6. REFERENCES
Bird, R. (2015). Thinking Functionally with Haskell. Cambridge, England: Cambridge University Press.
Davie, A. (1992). Introduction to Functional Programming Systems Using Haskell. Cambridge, England: Cambridge University Press.
Goerzen, J. & O'Sullivan, B. & Stewart, D. (2008). Real World Haskell. Sebastopol, CA: O'Reilly Media, Inc.
Hutton, G. (2007). Programming in Haskell. New York: Cambridge University Press.
Lipovača, M. (2011). Learn You a Haskell for Great Good!: A Beginner's Guide. San Francisco, CA: No Starch Press, Inc.
Thompson, S. (2011). The Craft of Functional Programming. Edinburgh Gate, Harlow, England: Pearson Education Limited.