Wednesday, April 3, 2013

HASKELL BEGINNER PROGRAM SKELETON: "READ AND SHOW" TUTORIAL

HASKELL BEGINNER PROGRAM SKELETON: "READ AND SHOW" TUTORIAL

REVISED: Monday, February 12, 2024




Haskell Beginner Program Skeleton: "Read and Show" Tutorial.

I. EXAMPLE OF READ AND SHOW

A. SKELETON

-- MODULE DECLARATION

-- IMPORTS

-- FUNCTIONS

-- MAIN PROGRAM

main :: IO ()
main = do  

B. FLESH ON BONES

1. SAVE

This example is intended to introduce you to input/output (IO) and iteractivity.

The example is also a review for using:

if <condition> then <true-value> else <false-value>

Notice the type of the entire if/then/else construction in the example is IO ().

Use your editor to save the following ReadAndShow.hs file:

module ReadAndShow where

main :: IO ()
main = do
        putStrLn "Please type a number then press Enter or type 0 and press Enter to exit."
        inpStr <- getLine
        let inpDouble = (read inpStr)::Double
        if inpDouble > 0
            then do
                putStrLn (show inpDouble ++  " multiplied by " ++  "2"++ " is " ++ show (inpDouble * 2))
                main           
            else
                return ()

2. LOAD

As shown below, load the above ReadAndShow.hs file into GHCi:

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

Now that we have loaded Main, we can run functions in GHCi that were defined in Main.

3. RUN

As shown below, run the function main, in GHCi:

Prelude>  main
Please type a number then press Enter or type 0 and press Enter to exit.
4.0
4.0 multiplied by 2 is 8.0
Please type a number then press Enter or type 0 and press Enter to exit.

0
Prelude>

4. COMPILE 

As shown below, compile ReadAndShow.hs in GHC:

Prelude>  :! ghc --make "*ReadAndShow"
[1 of 1] Compiling Main             ( ReadAndShow.hs, ReadAndShow.o )
Linking ReadAndShow.exe ...
Prelude>

The compile is shown so you know it compiles without error.

C. COMMENTS

Use the program shown above as an example. Rewrite the example and make it your own program.

Repeat 1. thru 3. above until your new program works the way you want it to work. Each time you make changes in your editor to your program, make sure you save the file and load it in GHCi.

Notice a module begins with the keyword module and is followed by the module name which is followed by the keyword where.

module ReadAndShow where

Also observe that using the arrow instead of the equal sign in the example shown below shows that getLine is not a real function and can return different values. This command means run the action getLine, and store the results we take in inpStr. Understanding the reason behind the choice of the word action instead of function is very important for your understanding of input/output (IO).

inpStr <- getLine

Other comments regarding this tutorial are discussed below:

1. Double

Haskell has a static type system. Everything in Haskell has a type. Types are labels values carry so we can reason about the values. In GHCi, the :t command, followed by any valid expression, tells us its type. Doing :t on an expression prints out the expression followed by :: and its type; :: is read as "has type of".

Types have their own labels, called kinds. A kind is the type of a type. We can examine the kind of a type by using the :kind or :k command in GHCi. A * means that the type is a concrete type. A concrete type is a type that does not take any type parameters. Values can only have types that are concrete types. A * is pronounced "star" or "type".

We can see what the instances of a typeclass are, by using the :info command in GHCi. 

Prelude>  :kind Double
Double :: *
Prelude>

Prelude>  :info Double
data Double = D# Double# -- Defined in `GHC.Types'
instance Enum Double -- Defined in `GHC.Float'
instance Eq Double -- Defined in `GHC.Classes'
instance Floating Double -- Defined in `GHC.Float'
instance Fractional Double -- Defined in `GHC.Float'
instance Num Double -- Defined in `GHC.Float'
instance Ord Double -- Defined in `GHC.Classes'
instance Read Double -- Defined in `GHC.Read'
instance Real Double -- Defined in `GHC.Float'
instance RealFloat Double -- Defined in `GHC.Float'
instance RealFrac Double -- Defined in `GHC.Float'
instance Show Double -- Defined in `GHC.Float'
Prelude>  

2. read

Types are written in capital case, so the a cannot be a type. Because it is not in capital case it is actually a type variable. That means that it can be of any type. Functions that have type variables are called polymorphic functions.

Prelude>  :type read
read :: Read a => String -> a
Prelude>

Prelude>  :info read
read :: Read a => String -> a -- Defined in `Text.Read'
Prelude>

The function read casts type String to another type.

3. asTypeOf

asTypeOf returns its first argument, but requires this to be the same type as its second argument.

Prelude>  :type asTypeOf
asTypeOf :: a -> a -> a
Prelude> 

Putting ` marks around an asTypeOf prefix function allows us to use it like an 'asTypeOf' infix function:

Prelude>  let f x = x * (read "410") `asTypeOf` x  -- Converts String to Double
Prelude> 

Prelude>  f 3.0
1230.0
Prelude>

This function was not used in the example; however, it was interesting enough to demonstrate its use. As shown above 'asTypeOf' works nicely with GHCi.

4. show

Prelude>  :type show
show :: Show a => a -> String
Prelude>

Prelude>  :info show
class Show a where
  ...
  show :: a -> String
  ...
  -- Defined in `GHC.Show'
Prelude>

The function show casts a type to a readable type String.

Think of read and show as being opposites: show lets you convert to String; and read converts from String.

5. :: type annotation

let inpDouble = (read inpStr)::Double

Type annotation is a way of explicitly saying what the type of an expression should be. We do that by adding :: at the end of the expression and then specifying a type.

II. CONCLUSION

In this tutorial, you have received an introduction to the Haskell beginner program skeleton "read and show" modual.

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