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