Chapter 5


Tips ⚠️️

  • Use try.purescript.org to test out the code examples in this book.
  • Whenever the example code starts with module Main where, make sure to clear out the code editor on try.purescript.org before pasting new code in. This will help to avoid unncessary errors

Output

So up to this point, we've typed a lot of code, but we've never seen it really do anything yet. Programming is all about input and output, and writing code could be considered input in its own right. But we're not going to have any fun until we get some output. I held off on the output aspect because I didn't want introduce things out of order, but no more! We're ready, sort of!

The Console

Now that we have functions, we can start displaying our data in the console. The console is a program that allows us to run applications via typing commands; it also provides us a quick and easy way to get input from the user and write output on the screen. We'll use it for output in our case.

If you're using try.purescript.org, you can bring up the console right in your browser by pressing ctrl shift J on linux/windows, or cmd option J on mac. This should work on any chrome-like browsers (Chrome, Chromium, Brave, Edge, etc) and firefox.

Easy output with spy

To get our first taste of writing output to the console, we're going to use a function called spy. This isn't the recommended way to really write output, but it will suffice for the time being.

For our first example, we'll start by writing the values of simple variables to the console.

module Main where
import Prelude
import Debug.Trace

coolInt :: Int
coolInt = spy "Cool num" 24

dumbBool :: Boolean
dumbBool = spy "Dumb!" true

Enter the above code into your code window and then open up the dev console. You should see

Cool num: 24
Dumb!: true

Imports

So whats happening here? We have two new things we haven't really seen before. First, we have the line

import Debug.Trace

We haven't talked about imports yet, but heres a quick rundown. People all over the world are writing code. If they publish that code online, we can pull it into our own program. The code we pull in are called libraries. Libraries are comprised of 1 or more modules.

Here, we import the Debug.Trace module from the library purescript-debug. (A listing of most published libraries can be found at pursuit.purescript.org). We'll take a deeper look into imports in a later chapter.

Polymorphism and the spy function

The next line of interest is:

coolInt = spy "Cool num" 24

This isn't totally weird, whats happening here? As mentioned above spy is a function. Lets look at it's type declaration

spy :: forall a. String -> a -> a

Ah! Another new thing! Whats this weird forall a. line? This is called polymorphism, the term sounds scary, but the concept isnt. forall a. is a sort of type declaration that says: "We have some type called a, and we dont care what it is! You can use anything for a and we'll be ok!"

What does it mean that a can be anything? Lets look at another example. Lets look at a function called identity

identity :: forall a. a -> a
identity x = x

Can you guess what identity does? Its a function that takes one parameter. This parameter can be anything, and all it does is return that parameter back to you.

Lets try it out!

module Main where
import Prelude

coolNum = identity 40
-- coolNum = 40

someText = identity "hello"
-- someText = "hello"

youCanDoIt = identity true
-- youCanDoIt = true

That doesn't seem very useful... Well, I won't go into the explanation of how identity can be useful, but this gives a good demonstration of how polymorphism works. We used three different types of values on the identity function: An Int 40, a String "hello", and a Boolean true; and it happily accepted them. Contrast this with the following

module Main where
import Prelude

numIdentity :: Int -> Int
numIdentity x = x

-- Compile error here
someText = numIdentity "Hello"

The above doesn't work because numIdentity needs it's first parameter to be an Int. This isn't the case with identity, identity says "You can give me anything and I'll still work"! We'll take a closer look at polymorphism later as well.

Back to the spy

So let's look at the type of spy again

spy :: forall a. String -> a -> a

I won't show the actual definition of spy, but essentially, it takes a String and an a (which can be anything); writes them to the console, and then returns the a parameter. So its sort of like identity, but with some hidden side effects.

So hopefully our original block of code makes a little more sense now

module Main where
import Prelude
import Debug.Trace

coolInt :: Int
coolInt = spy "Cool num" 24

dumbBool :: Boolean
dumbBool = spy "Dumb!" true

Spy the functions

The way we used spy up above is not how its typically used. There's no need to use spy on plain old variables, it's more useful in functions.

module Main where
import Prelude
import Debug.Trace

doubleTheBank :: Int -> Int
doubleTheBank money =
  spy "double the money is" (money * 2)

johnBank :: Int
johnBank = doubleTheBank 100

tobyBank :: Int
tobyBank = doubleTheBank (400)

Now we'll see in the console

double the money is: 200
double the money is: 800

Each time doubleTheMoney is called, we'll get some output in the console.

So there we go, here's our first taste of output. There's more official ways to get output, but we need to learn a bit more before we can tackle that task.

Summary

We can use the spy function to output the values of variables to the console.

In the web browser, you can open the comsole by pressing ctrl shift J on linux/windows, or cmd option J on mac (for chrome based browsers and firefox)

In order to use spy, you must import the module Debug.Trace

spy uses a polymorphic parameter, meaning you can use any value for that parameter.

Heres the type declaration for spy

spy :: forall a. String -> a -> a

Heres an example using spy

module Main where

import Prelude
import Debug.Trace

doubleNumber x =
  (spy "Doubling" x) * 2

jakesAge = doubleNumber 20
bensMoney = doubleNumber 4

The above example will output

Doubling: 20
Doubling: 4

Self Practice

Lets write a greeting function. Write a function that takes a string parameter and says hello to it before returning it. For example, if the string is "Mr.X", then in the console, we should see

Hello: Mr.X
Answer
greeting :: String -> String
greeting name =
  spy "Hello" name