Showing posts with label do. Show all posts
Showing posts with label do. Show all posts

Thursday, January 19, 2017

HASKELL AND YOUR AGE BY CHOCOLATE

HASKELL AND YOUR AGE BY CHOCOLATE

REVISED: Saturday, October 5, 2024


1. INTRODUCTION

This tutorial is for having fun with Haskell.

2. HASKELL PROGRAM

The Haskell program is as follows:

-- C:\Users\Tinnel\Haskell2024\age.hs

import Data.List
import System.IO

main :: IO ()  -- Has type I/O action.
main = do {  putStrLn ""  -- putStrLn Has type I/O action.
           ; putStrLn "=========================================================="
           ; putStrLn ""
           ; putStrLn "CALCULATING YOUR AGE BY CHOCOLATE!"
           ; putStrLn ""
           ; putStrLn "First, type a positive integer from 1 to 10 indicating how"
           ; putStrLn "often you crave chocolate each week, then press Enter."
           ; cewS <- getLine -- getLine is a function, getLine :: IO String
           ; putStrLn ""
           ; let runTot1I = (read cewS)::Integer
           ; let runTot1S = show runTot1I
           ; putStrLn ("Running Total: " ++ runTot1S)
           ; putStrLn ""
           ; putStrLn "=========================================================="
           ; putStrLn ""
           ; let cewI = (read cewS)::Integer
           ; let cewIx2I = cewI * 2
           ; let cewIx2S = show cewIx2I
           ; putStrLn ("Second, we multiply " ++ cewS ++ " by 2 which equals " ++ cewIx2S ++ ".")
           ; putStrLn ""
           ; let runTot2I = runTot1I * 2
           ; let runTot2S = show runTot2I
           ; putStrLn ("Running Total: " ++ runTot2S)
           ; putStrLn ""
           ; putStrLn "=========================================================="
           ; putStrLn ""
           ; let cewIp5I = cewIx2I + 5
           ; let cewIp5S = show cewIp5I
           ; putStrLn ("Third, we add 5 to our running total which equals " ++ cewIp5S ++ ".")
           ; putStrLn ""
           ; let runTot3I = runTot2I + 5
           ; let runTot3S = show runTot3I
           ; putStrLn ("Running Total: " ++ runTot3S)
           ; putStrLn ""
           ; putStrLn "=========================================================="
           ; putStrLn ""
           ; let cewIp5x50I = cewIp5I * 50
           ; let cewIp5x50S = show cewIp5x50I
           ; putStrLn ("Fourth, we multiply our running total by 50 which equals " ++ cewIp5x50S ++ ".")
           ; putStrLn ""
           ; let runTot4I = runTot3I * 50
           ; let runTot4S = show runTot4I
           ; putStrLn ("Running Total: " ++ runTot4S)
           ; putStrLn ""
           ; putStrLn "=========================================================="
           ; putStrLn ""
           ; putStrLn "Fifth, type the current year date as a positive integer; e.g., 2017"
           ; putStrLn "then press Enter."
           ; yearS <- getLine -- getLine is a function, getLine :: IO String
           ; putStrLn ""
           ; putStrLn ("Running Total: " ++ runTot4S)
           ; putStrLn ""
           ; putStrLn "=========================================================="
           ; putStrLn ""
           ; let yearI = (read yearS)::Integer
           ; let runTotI = cewIp5x50I + (yearI - 250)
           ; let runTotS = show runTotI
           ; putStrLn "Sixth, we subtract 250 from the current year; e.g., 2017 - 250 = 1767"
           ; putStrLn ("and add the result to our running total which equals " ++ runTotS ++ ".")
           ; putStrLn ""
           ; let runTot6I = runTot4I + (yearI - 250)
           ; let runTot6S = show runTot6I
           ; putStrLn ("Running Total: " ++ runTot6S)
           ; putStrLn ""
           ; putStrLn "=========================================================="
           ; putStrLn ""
           ; putStrLn "Seventh, if you have not had your birthday this year type the integer 1."
           ; putStrLn "If you have had your birthday this year type zero; e.g., 0."
           ; putStrLn "Then press Enter."
           ; birthdayS <- getLine -- getLine is a function, getLine :: IO String
           ; putStrLn ""
           ; putStrLn ("Running Total: " ++ runTot6S)
           ; putStrLn ""
           ; putStrLn "=========================================================="
           ; putStrLn ""
           ; let birthdayI = (read birthdayS)::Integer
           ; let runTotMI = (runTotI - birthdayI)
           ; let runTotMS = show runTotMI
           ; putStrLn "Eighth, we subtract 1 or 0 from the running total."
           ; putStrLn ""
           ; putStrLn ("Now our running total equals " ++ runTotMS ++ ".")
           ; putStrLn ""
           ; let runTot8I = (runTot6I - birthdayI)
           ; let runTot8S = show runTot8I
           ; putStrLn ("Running Total: " ++ runTot8S)
           ; putStrLn ""
           ; putStrLn "=========================================================="
           ; putStrLn ""
           ; putStrLn "Ninth, type the year of your birth; e.g., 1992"
           ; putStrLn "then press Enter."
           ; birthYearS <- getLine -- getLine is a function, getLine :: IO String
           ; putStrLn ""
           ; putStrLn ("Running Total: " ++ runTot8S)
           ; putStrLn ""
           ; putStrLn "=========================================================="
           ; putStrLn ""
           ; let birthYearI = (read birthYearS)::Integer
           ; let runTotBYI = (runTotMI - birthYearI)
           ; let runTotBYS = show runTotBYI
           ; putStrLn "Tenth, we subtract the year you were born from the running total."
           ; putStrLn ""
           ; putStrLn ("Now our running total equals " ++ runTotBYS ++ ".")
           ; putStrLn ""
           ; let runTot10I = (runTot8I - birthYearI)
           ; let runTot10S = show runTot10I
           ; putStrLn ("Running Total: " ++ runTot10S)
           ; putStrLn ""
           ; putStrLn "=========================================================="
           ; putStrLn ""
           ; putStrLn "The running total's first two digits are how often you crave chocolate each week."
           ; putStrLn ""
           ; putStrLn "The last two digits of the running total are your Age By Chocolate."
           ; putStrLn ""
           ; putStrLn ("Running Total: " ++ runTot10S)
           ; putStrLn ""
           ; putStrLn "=========================================================="
           ; putStrLn ""
          }
--

3. GHCi RUN

GHCi, version 9.8.1: http://www.haskell.org/ghc/  :? for help
Prelude> :l age
[1 of 1] Compiling Main             ( age.hs, interpreted )
Ok, modules loaded: Main.

*Main> main
==========================================================

CALCULATING YOUR AGE BY CHOCOLATE!

First, type a positive integer from 1 to 10 indicating how
often you crave chocolate each week, then press Enter.
10

Running Total: 10

==========================================================

Second, we multiply 10 by 2 which equals 20.

Running Total: 20

==========================================================

Third, we add 5 to our running total which equals 25.

Running Total: 25

==========================================================

Fourth, we multiply our running total by 50 which equals 1250.

Running Total: 1250

==========================================================

Fifth, type the current year date as a positive integer; e.g., 2017
then press Enter.
2017

Running Total: 1250

==========================================================

Sixth, we subtract 250 from the current year; e.g., 2017 - 250 = 1767
and add the result to our running total which equals 3017.

Running Total: 3017

==========================================================

Seventh, if you have not had your birthday this year type the integer 1.
If you have had your birthday this year type zero; e.g., 0.
Then press Enter.
0

Running Total: 3017

==========================================================

Eighth, we subtract 1 or 0 from the running total.
Now our running total equals 3017.

Running Total: 3017

==========================================================

Ninth, type the year of your birth; e.g., 1992
then press Enter.
1992

Running Total: 3017

==========================================================

Tenth, we subtract the year you were born from the running total.
Now our running total equals 1025.

Running Total: 1025

==========================================================

The first two digits of the running total are how often you crave chocolate each week.
The last two digits of the running total are your Age By Chocolate.

Running Total: 1025

==========================================================
*Main>

4. CONCLUSION

You can have fun with Haskell.

5. 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.



Tuesday, January 10, 2017

HASKELL PROOF BY CONTRADICTION EXAMPLE 1

HASKELL PROOF BY CONTRADICTION EXAMPLE 1

REVISED: Saturday, October 5, 2024


1. INTRODUCTION

1.1 GIVEN

1.1.1 Consider the following proposition:

For all n in the set of positive Natural numbers, the function f n = n ^ 2 + n + 41 is a prime number is True.

1.1.2 Definition

A Prime Number is a whole number greater than or equal to 2 which has two and only two factors; for example, it can be divided without a remainder only by 1 and itself.

2. HASKELL PROGRAM

2.1 TO BE PROVED

We will use a proof by contradiction.

Therefore, we assume that the statement of the proposition that for all n in the set of positive Natural numbers, the function f n = n ^ 2 + n + 41 is a prime number is False.

2.2 PROOF

The Haskell program used for the proof is as follows:

-- C:\Users\Tinnel\Haskell2024\proof1.hs

import Data.Char
import Data.List
import Data.List (elemIndex)
import Data.Map
import Data.Maybe
import Data.Set
import System.IO
--
--
main :: IO ()    -- Has type I/O action.
main = do {  putStrLn ""    -- putStrLn Has type I/O action.
                   ; putStrLn "======================================================"
                   ; putStrLn ""
                   ; putStrLn "Prove the proposition that for all n in the set of positive Natural numbers, the function"
                   ; putStrLn ""
                   ; putStrLn "f n = n ^ 2 + n + 41"
                   ; putStrLn ""
                   ; putStrLn "is a prime number is False."
                   ; putStrLn ""
                   ; putStrLn "======================================================"
                   ; putStrLn ""
                   ; putStrLn "Type a positive integer value for n then press Enter."
                   ; s <- getLine -- getLine is a function, getLine :: IO String
                   ; putStrLn ""
                   ; putStrLn "======================================================"
                   ; putStrLn ""
                   ; putStrLn ("Computing the function with n equal to " ++ s ++ ".")
                   ; putStrLn ""
                   ; let n = (read s)::Integer  -- Type converted from IO String s to Integer n.
                   ; let z = f n  -- z is the integer prime number computed by n.
                   ; let zS = show z  -- Type converted from Integer z to String z.
                   ; putStrLn ("f n = n ^ 2 + n + 41 equals " ++ zS ++ ".")
                   ; putStrLn ""
                   ; putStrLn "======================================================"
                   ; putStrLn ""
                   ; putStrLn "The list of the first 300 prime numbers starting with 2 is as follows:"
                   ; putStrLn ""
                   ; print p  -- The list of prime numbers.
                   ; putStrLn ""
                   ; putStrLn "======================================================"
                   ; putStrLn ""
                   ; putStrLn ("QUESTION: True or False is " ++ zS ++ " a prime number?")
                   ; putStrLn ""
                   ; let i = if elem z p == True then "True" else "False"
                   ; putStrLn ("ANSWER: " ++ i ++ ".")
                   ; putStrLn ""
                   ; putStrLn ""
                   ; putStrLn ""
                 }
--
--
-- t computes prime numbers.
t :: Integral a => [a] -> [a]
t (p : xs) = p : t [x | x <- xs, x `mod` p /= 0]

-- primes is a list of prime numbers computed by t.
primes :: [Integer]
primes = t [2..]  -- Starting with 2 because zero and 1 are not prime numbers.
                         -- However, main can compute n = 0, and n = 1.

-- p is a list of prime numbers taken from those computed by t.
p :: [Integer]
p = take 300 primes

-- f n computes each number compared to the list p for prime.
f :: Num a => a -> a
f n = n ^ 2 + n + 41

-- read :: Read a => String -> a
-- (==) :: (Eq a) => a -> a -> Bool


3. GHCi RUN

GHCi, version 9.8.1: http://www.haskell.org/ghc/  :? for help
Prelude> :l proof1
[1 of 1] Compiling Main             ( proof1.hs, interpreted )
Ok, modules loaded: Main.

*Main> main

=========================================================================

Prove the proposition that for all n in the set of positive Natural numbers, the function

f n = n ^ 2 + n + 41

is a prime number is False.

=========================================================================

Type a positive integer value for n then press Enter.
5

=========================================================================

Computing the function with n equal to 5.

f n = n ^ 2 + n + 41 equals 71.

=========================================================================

The list of the first 300 prime numbers starting with 2 is as follows:

[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997,1009,1013,1019,1021,1031,1033,1039,1049,1051,1061,1063,1069,1087,1091,1093,1097,1103,1109,1117,1123,1129,1151,1153,1163,1171,1181,1187,1193,1201,1213,1217,1223,1229,1231,1237,1249,1259,1277,1279,1283,1289,1291,1297,1301,1303,1307,1319,1321,1327,1361,1367,1373,1381,1399,1409,1423,1427,1429,1433,1439,1447,1451,1453,1459,1471,1481,1483,1487,1489,1493,1499,1511,1523,1531,1543,1549,1553,1559,1567,1571,1579,1583,1597,1601,1607,1609,1613,1619,1621,1627,1637,1657,1663,1667,1669,1693,1697,1699,1709,1721,1723,1733,1741,1747,1753,1759,1777,1783,1787,1789,1801,1811,1823,1831,1847,1861,1867,1871,1873,1877,1879,1889,1901,1907,1913,1931,1933,1949,1951,1973,1979,1987]

=========================================================================

QUESTION: True or False is 71 a prime number?

ANSWER: True.

4. TRUTH TABLE

Running the Haskell program for each element of n we obtain the truth table shown below:

n    f n = n^2 + n + 41      Prime
---- ------------------------     -------
  0                           41    True
  1                           43    True
  2                           47    True
  3                           53    True
  4                           61    True
  5                           71    True
  6                           83    True
  7                           97    True
  8                         113    True
  9                         131    True
10                         151    True
11                         173    True
12                         197    True
13                         223    True
14                         251    True
15                         281    True
16                         313    True
17                         347    True
18                         383    True
19                         421    True
20                         461    True
21                         503    True
22                         547    True
23                         593    True
24                         641    True
25                         691    True
26                         743    True
27                         797    True
28                         853    True
29                         911    True
30                         971    True
31                       1033    True
32                       1097    True
33                       1163    True
34                       1231    True
35                       1301    True
36                       1373    True
37                       1447    True
38                       1523    True
39                       1601    True
40                       1681    False  Q.E.D.
41                       1763    False
42                       1847    True
43                       1933    True
44                       2021     Outside of the first 300 prime number range.

5. CONCLUSION

The proposition that for all n in the set of positive Natural numbers, the function f n = n ^ 2 + n + 41 is a prime number is False.

As shown above, you must be careful when concluding whether a proof is True or False. The first 39 tests would lead most people to assume f n = n^2 + n + 41 could be used to compute prime numbers. However tests 40 and 41 show the proposition is not True, it is False.

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.


Thursday, January 31, 2013

HASKELL INPUT AND OUTPUT (IO)

HASKELL INPUT AND OUTPUT (IO)




REVISED: Monday, October 21, 2024




Haskell Input and Output (IO).

Good Haskell style involves separating pure code from code that performs IO.

I.  HASKELL IMPORT

I am asking you to input the following imports so I can use them in examples "I. A." and "I. B." shown below. I also want to demonstrate the dangers of using imports without knowing their contents.

Prelude> import Control.Arrow
Prelude>

Prelude> import Control.Monad
Prelude>

Prelude> import Data.ByteString
Prelude>

Prelude> import Data.Char
Prelude>

Prelude> import Data.List 
Prelude>

Prelude> import System.IO  
Prelude>

Prelude> import System.Directory
Prelude>

Prelude> import System.Environment 
Prelude>

Prelude> import System.IO.Error
Prelude>

Prelude> import System.Random 
Prelude>

A. :SHOW IMPORTS

Prelude> :show imports
import Prelude -- implicit
import Control.Arrow
import Control.Monad
import Data.ByteString
import Data.Char
import Data.List
import System.IO
import System.Directory
import System.Environment
import System.IO.Error
import System.Random
:module +*Main -- added automatically
Prelude>

Notice Data.ByteString is in the above list of imports.

B. :MODULE -M

Where M is the name of the import you want to remove, imports can be removed from the current scope, using the syntax :module -M as shown below:

Prelude> :module -Data.ByteString
Prelude>

Prelude> :show imports
import Prelude -- implicit
import Control.Arrow
import Control.Monad
import Data.Char
import Data.List
import System.IO
import System.Directory
import System.Environment
import System.IO.Error
import System.Random
:module +*Main -- added automatically
Prelude>

Notice Data.ByteString is not in the above list of imports.

The full syntax of the :module command is: 

:module [+|-] [*]mod1 ... [*]modn

Using the + form of the module command adds modules to the current scope, and - removes them.

You cannot add a module to the scope if it is not loaded.

II.  HASKELL "IO ACTIONS"

If you did:

Prelude> import Data.ByteString
Prelude>

Prelude> import System.IO
Prelude>

and did not do:

Prelude> :module -Data.ByteString
Prelude>

as shown above in I., you will receive an "ambiguous occurrence" error message from GHCi when you do the examples shown below. GHCi will not be able to determine which import you are referring to. Therefore, you have to be very careful when using multiple imports. It is a good idea to know everything contained in an import before you use it.

The GHCi prompt operates as if the lines were being typed into a do block in the IO monad.

Prelude> :type putStrLn
putStrLn :: String -> IO ()
Prelude>

putStrLn gives back nothing, ().

Prelude>  :t getLine
getLine :: IO String
Prelude>

getLine gives back a String to use. 

Prelude> :type readFile
readFile :: FilePath -> IO String
Prelude>

IO is Haskell’s way of representing that putStrLn and readFile are not really functions, in the pure mathematical sense, they are “IO Actions”. Typical actions include reading and setting global variables, writing files, reading input, and opening windows.

The -> drawn from notation is a way to get the value out of an action. The (), pronounced “unit”, is an empty tuple indicating that there is no return value from putStrLn. This is similar to "void" in Java or C.

If we are taking data out of an IO action, we can only take it out when we are inside another IO action. In other words, to get the value out of an IO action, you have to perform it inside another IO action by binding it to a name with the -> drawn from arrow function. Variables bound by the -> drawn from arrow function are lambda bound and are thus monomorphic. IO actions will only be performed when they are given the name of main or when they are inside a bigger IO action that was composed with a do block. Therefore, when you want to bind the results of IO actions to names, use the -> drawn from arrow function.

The only way to use things with an IO type is to combine them with functions using do notation which can include if/then/else and case/of. In a do expression, every line is a monadic value. We code do and then we lay out a series of steps, like we would in an imperative program chaining computations. Each of these steps is an IO action, a control flow expression. A statement is either an action, a pattern bound to the result of an action using <-, or a set of local definitions introduced using letBy putting them together with do syntax, we glue them into one IO action. do works with any monad, the action that we get has a type of IO (), because that is the type of the last IO action inside the doWhen sequencing actions with do notation, each “bare” line, lines that do not have a <- in them, must have type IO ().

do can replace the  >> pronounced "then" operator.

Prelude> :type (>>)
(>>) :: Monad m => m a -> m b -> m b
Prelude>

We can use do syntax to glue together several IO actions into one.  The value from the last action in a do block is bound to the do block result.

You always do IO inside a do statement, using the IO monad. This way you are guaranteed that IO actions are executed in order.

$ is pronounced "apply." When a $ is encountered, the expression on its right is applied as the parameter to the function on its left. In other words the $ is the same as a ( and the closing ) is the end of the line. For example (1, 2, 3, 4) is the same as $ 1, 2, 3, 4

You cannot use $ if the closing ) would not appear at the end of the line.

A. REVIEW

First, we will review GHCi "ambiguous occurrence" error messages

Try doing the following examples. You will receive another GHCi "ambiguous occurrence" error message. The point I am repeatedly trying to make is you should understand the contents of imports before using them.

Exit out of GHCi and then reload GHCi. Use the following commands to see what you start out with in GHCi when it is first loaded.

Prelude>  :show
options currently set: +t   -- +t prints type after evaluation
base language is: Haskell2010
with the following modifiers:
  -XNoDatatypeContexts
  -XNondecreasingIndentation
GHCi-specific dynamic flag settings:
other dynamic, non-language, flag settings:
  -fimplicit-import-qualified
warning settings:
Prelude>

Prelude>  :show imports
import Prelude -- implicit
Prelude>  

Second, we will show a basic example of putStrLn:

Prelude> :{
Prelude| do {
Prelude| putStrLn "Hello, World!"
Prelude| }
Prelude| :}
Hello, World!
it :: ()
Prelude>

Third, we will show an example of using getLine and $ with putStrLn:

Prelude> :{
Prelude| let prRev = do {
Prelude|      inp <- getLine;
Prelude|      putStrLn $ reverse inp;
Prelude| }
Prelude| :}
Prelude| 
Prelude>

Prelude> :type prRev
prRev :: IO ()
Prelude>

Prelude> prRev
Hello, World!
!dlroW ,olleH
Prelude>

B. OUTPUT FUNCTIONS

These functions write to the standard output device, which is normally the user's terminal.

Prelude> import Data.Char
Prelude>

Prelude> :type print
print :: Show a => a -> IO ()
Prelude>

Prelude> :type putChar
putChar :: Char -> IO ()
Prelude>

The unit type (), which is similar to void in other languages, is used by actions which return no values.  return packs up a value into an IO box. <- extracts the value out of an IO box and is read as "comes from". In other words, return turns a value into an IO action and <- turns an IO action into a regular value.

"Copy paste" the following Haskell script into your text editor and "save as" TestReturn.hs  to your working directory:

-- TestReturn.hs

module TestReturn where

main = do putStrLn "Shall I quit the program? y/n"
          ans <- getLine
          if ans /= "y"
             then do putStrLn "Thank you! I enjoy working with you!"
                     main
             else do putStrLn "Nice working with you my friend! Happy trails, until we meet again!"
                     return ()  -- We created an IO that does not do anything so the program can exit.

As shown below, load the TestReturn program, then run the module TestReturn function main, in GHCi:

Prelude>  :load TestReturn
[1 of 1] Compiling TestReturn       ( TestReturn.hs, interpreted )
Ok, modules loaded: TestReturn.
Prelude>

Prelude>  main
Shall I quit the program? y/n
n
Thank you! I enjoy working with you!
Shall I quit the program? y/n
y
Nice working with you my friend! Happy trails, until we meet again!
it :: ()
Prelude>  

PS C:\Users\User\tinnel\Haskell 2024\newProjects> ghci
GHCi, version 9.4.8: https://www.haskell.org/ghc/  :? for help
ghci> :load TestReturn.hs
[1 of 1] Compiling TestReturn       ( TestReturn.hs, interpreted )
Ok, one module loaded.
ghci> main
Shall I quit the program? y/n
n
Thank you! I enjoy working with you!
Shall I quit the program? y/n
y
Nice working with you my friend! Happy trails, until we meet again!
ghci>

putStrLn is a function that takes a single argument of type String and produces a value of type IO (). The IO () signifies an executable action that returns a value of type (). When we supply putStrLn with a String argument we get an executable IO action which will print the supplied String.

Prelude> :type putStr
putStr :: String -> IO ()
Prelude>

Prelude> putStr "Hello"
Helloit :: ()   -- Notice that two lines combine without a \n newline escape sequence!
Prelude> 

Prelude> putStr "Hello\n"
Hello   -- The \n newline escape sequence does a carriage return.
it :: ()Prelude>

Prelude> :type putStrLn
putStrLn :: String -> IO ()
Prelude>

Prelude> :type putStrLn "abcdefghijklmnopqrstuvwxyz"
putStrLn "abcdefghijklmnopqrstuvwxyz" :: IO ()
Prelude>

C. INPUT FUNCTIONS

These functions read input from the standard input device, which is normally the user's keyboard. 

Prelude> :type getChar
getChar :: IO Char
Prelude>

When the function getChar is invoked, it will perform an action which returns a character.

Prelude> :type getLine
getLine :: IO String
Prelude>

Should be read as, "getLine is an action that, when performed, produces a string".

Prelude> :type getContents
getContents :: IO String
Prelude>

Prelude> :type interact
interact :: (String -> String) -> IO ()
Prelude>

Prelude> :type readIO
readIO :: Read a => String -> IO a
Prelude>

Prelude> :type readLn
readLn :: Read a => IO a
Prelude>

Use let bindings to bind pure expressions, normal non-IO expressions, to names. For example:

Prelude> let y = 12
y :: Num a => a
Prelude>

Prelude> y
12
it :: Num a => a
Prelude>

As shown above, let bindings do not automatically print the value bound.

As shown below, when we type out a monadic IO action in GHCi and press Enter, the IO action will be performed:

Prelude> putStrLn "Hello, World!" 
Hello, World!
it :: ()
Prelude>

You are always writing code in the IO monad when you are using GHCi.  GHCi evaluates the IO action, then calls show on the IO action, and prints the string to the terminal using putStrLn implicitly. 

D. IO EXAMPLE 1

"Copy, Paste" the following program into your text editor and "File, Save As" Point.hs to your working directory:

-- Point.hs

module Point where

point :: IO (Char,Char)
point = do {  x <- getChar
                    ; getChar
                   ; y <- getChar
                   ; return (x,y)
                 }

Load Point.hs into GHCi as follows:

Prelude>  :load Point.hs
[1 of 1] Compiling Main             ( point.hs, interpreted )
Ok, modules loaded: Main.
Prelude>

From GHCi call the Point.hs program as follows:

Prelude>  Point.hs
8  -- You will be prompted twice. At each prompt type an Integer then press Enter.
2
('8','2')  -- The output will return a tuple point :: IO (Char,Char).
Prelude>

PS C:\Users\User\tinnel\Haskell 2024\newProjects> ghci
GHCi, version 9.4.8: https://www.haskell.org/ghc/  :? for help
ghci> :load Point.hs
[1 of 1] Compiling Point            ( Point.hs, interpreted )
Ok, one module loaded.
ghci> point
8
2
('8','2')
ghci> :quit
Leaving GHCi.
PS C:\Users\User\tinnel\Haskell 2024\newProjects> 

E. IO EXAMPLE 2

"Copy, Paste" the following program into your text editor and "File, Save As" Name.hs to your working directory:

-- Name.hs

module Name where

import Data.List()
import System.IO

main :: IO ()
main = do {  putStrLn "What is your name?"
                    ; yn 
 <- getLine
<- getline="" span="">                     ; putStrLn ("Hello " ++ yn ++ "!" ) 
                  }

Load Name.hs into GHCi as follows:

Prelude>  : load Name.hs
[1 of 1] Compiling Main             ( name.hs, interpreted )
Ok, one module loaded.
*Main>

From GHCi call the Name program as follows:

*Main>  main
What is your name?
Ron
Hello Ron!
*Main> 

PS C:\Users\User\tinnel\Haskell 2024\newProjects> ghci
GHCi, version 9.4.8: https://www.haskell.org/ghc/  :? for help
ghci> :load Name.hs
[1 of 1] Compiling Name             ( Name.hs, interpreted )
Ok, one module loaded.
ghci> main
What is your name?
Ron
Hello Ron!
ghci> :quit
Leaving GHCi.
PS C:\Users\User\tinnel\Haskell 2024\newProjects> 

III. TEXT FORMAT

Keep lines to no more than 80 columns.

Do not use tabs.

Use CamelCase, do not use underscores.

Do not leave trailing white space in your lines of code.

Do not use braces and semicolons.

Use spaces for indenting.

Indent code blocks such as "let, where, do, and of" 4 spaces.

Indent "where" keyword 2 spaces.

Indent "where" definitions 2 spaces.

Indent "guards" 2 spaces.

IV. CONCLUSION

In this tutorial, you have received an introduction to Haskell input and output (IO).

V. 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.