How the Computer Executes FP Programs

Or "What does sequential computation look like using Monads"

Below, we'll be defining a long chain of nested functions. Since functions usually place their argument on the right of the body like this...

(\x -> body) actualArgument

... we'll be putting it on the left using #

actualArgument # (\x -> body)

In other words...

function      arg == arg # function
(\x -> x + 1) arg == arg # (\x -> x + 1)

This will help the upcoming examples be much clearer and more understandable.

Using this type and its instance...

data Box a = Box a

instance Functor Box where
  map :: forall a b. (a -> b) -> Box a -> Box  b
  map f (Box a) = Box (f a)

instance Apply Box where
  apply :: forall a b. Box (a -> b) -> Box a -> Box  b
  apply (Box f) (Box a) = Box (f a)

instance Bind Box where
  bind :: forall a b. Box a -> (a -> Box b) -> Box b
  bind (Box a) f = f a

instance Applicative Box where
  pure :: forall a. a -> Box a
  pure a =  Box a

... we will translate the Javascript "program" below...

const four = 4
const five = 1 + four
const five_string = toString(five); // or whatever the function called
print(five_string); // print the String to the console, which returns nothing

... into its corresponding Purescript "program" (next).

In the following snippet of code, you will need to scroll to the right, so that the a previous reduction aligns with the next reduction. Note: Read through this and practice writing it out multiple times until you get sick of it as this is at the heart of FP programming! Failure to understand this == Failure to write FP code. Here's the code:

unsafePerformEffect :: forall a. Box a -> a
unsafePerformEffect (Box a) = a

-- Compute what the final Box value is in `main`
-- and then call `unsafePerformEffect` on the final Box
runProgram :: Unit
runProgram = unsafePerformEffect main

main :: Box Unit
main =
  (Box 4) >>= (\four -> Box (1 + four) >>= (\five -> Box (show five) >>= (\five_string -> print five_string)))

-- Step 1: De-infix the first '>>=' alias back to bind
  bind (Box 4)  (\four -> Box (1 + four) >>= (\five -> Box (show five) >>= (\five_string -> print five_string)))

-- Step 2: Look up Box's bind implementation...
--   ...and replace the left-hand side with the right-hand side
            4 # (\four -> Box (1 + four) >>= (\five -> Box (show five) >>= (\five_string -> print five_string)))

            -- Step 3: Apply the arg to the function (i.e. replace "four" with 4)
                (\4    -> Box (1 + 4   ) >>= (\five -> Box (show five) >>= (\five_string -> print five_string)))

                -- Step 4: Reduce the function to its body
                          Box (1 + 4   ) >>= (\five -> Box (show five) >>= (\five_string -> print five_string))

                          -- Step 5: Reduce the argument in "Box (1 + 4)" to "Box 5"
                          Box (5       ) >>= (\five -> Box (show five) >>= (\five_string -> print five_string))

                          -- Step 6: Remove the parenthesis
                          Box  5         >>= (\five -> Box (show five) >>= (\five_string -> print five_string))

                          -- Step 7: Remove the extra whitespace and push right
                                   Box 5 >>= (\five -> Box (show five) >>= (\five_string -> print five_string))

                                   -- Step 8: Repeat Steps 1-7 for the next ">>="
                                   bind (Box 5)  (\five -> Box (show five) >>= (\five_string -> print five_string))

                                             5 # (\five -> Box (show five) >>= (\five_string -> print five_string))

                                                 (\5    -> Box (show 5   ) >>= (\five_string -> print five_string))

                                                           Box (show 5   ) >>= (\five_string -> print five_string)

                                                           Box ("5"      ) >>= (\five_string -> print five_string)

                                                           Box  "5"        >>= (\five_string -> print five_string)

                                                                   Box "5" >>= (\five_string -> print five_string)

                                                                   -- Step 8: Repeat Steps 1-6 for the next ">>="
                                                                   bind (Box "5")  (\five_string -> print five_string)

                                                                             "5" # (\five_string -> print five_string)

                                                                                   (\"5"         -> print "5")

                                                                                                    print "5"

                                                                  -- Step 9: Look up `print`'s definition
                                                                  --
                                                                  --   print :: forall a. a -> Box Unit
                                                                  --   print a =
                                                                  --      -- Assume that 'a' is printed to the console
                                                                  --      Box unit
                                                                  --
                                                                  -- ... and replace the LHS with RHS

                                                                                                     Box unit

                                                                  -- Step 10a: Shift everything to the left again
-- 10b) ... and re-expose the 'main' function:
main :: Unit
main = Box unit -- after all the earlier computations...

-- Step 12: call `unsafePerformEffect` to get the final Box's value
runProgram :: Unit
runProgram = unsafePerformEffect (Box unit)
-- becomes
runProgram :: Unit
runProgram = unit

Now go read the code snippet above again and write it out!

Do and Ado Notation

At this point, you should look back at the Syntax/Prelude-Syntax folder and read through its files. Feel free to ignore the Qualified Do/Ado Explained file and those that follow.

Once finished, read the next file.