CS 331 Spring 2013  >  Lecture Notes for Wednesday, February 27, 2013

# CS 331 Spring 2013 Lecture Notes for Wednesday, February 27, 2013

### String Conversion

#### Strings & I/O

In many languages, conversion to & from a string is mixed up together with I/O. This makes sense, because when we do text I/O, the values we send and receive must, in the end, be composed of characters. For example, in C++:

[C++]

int x;
cout << x;


The second line above converts the value of x to a string, and then sends it to cout.

In Haskell, string conversion and I/O are kept a bit more separate. We look first at string conversion

#### Function show

Function show converts pretty much anything to a String. This function is overloaded for any type in class Show.

> show 345
"345"
> length (show 345)  -- length of String
3
> length 345         -- 345 is not a String
ERROR ...


#### Function read

Function read can convert a String to pretty much anything. This function is overloaded for any type in class Read.

> read "345"
ERROR ...


We may need to indicate the type to convert to. Often the compiler can determine this by looking at what is done with the return value of read.

> 2 + read "345"    -- Integer context
347
> 2.0 + read "345"  -- Double context
347.0


An interesting way to specify a type requirement is to use function asTypeOf. This is defined as follows.

asTypeOf :: a -> a -> a
asTypeOf x _ = x


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

> (read "345") asTypeOf 12    -- Convert to Integer
345
> (read "345") asTypeOf 12.0  -- Convert to Double
345.0


### Simple Output

#### I/O Actions

An I/O action is a type of value. We do I/O by returning an I/O action to the outside world.

sayHowdyNewLine = putStrLn "Howdy!"


> :t sayHowdyNewLine
sayHowdyNewLine :: IO ()
> sayHowdyNewLine
Howdy!


Function putStr takes a String parameter and putStr returns an I/O action. When returned to the outside world, this I/O action causes the string to be printed. Function putStrLn is the same, except that it adds a newline on the end.

> :t putStr
putStr :: String -> IO ()


Saying print x is the same as putStrLn (show x).

#### do Blocks

A do block combines multiple I/O actions into a single I/O action.

printMessages = do
putStrLn "Hello"
putStr "Here is a number: "
print (7*8 + 15)
putStrLn "Bye!"


> :t printMessages
printMessages :: IO ()
> printMessages
Hello
Here is a number: 71
Bye!


We can nest do blocks.

printMessages2 = do
putStrLn "My"
do
putStrLn "dog"
putStrLn "has"
putStrLn "fleas."


> :t printMessages2
printMessages2 :: IO ()
> printMessages2
My
dog
has
fleas.


### Simple Input

An I/O action is essentially a side effect wrapping a value. The above I/O actions all wrap “nothing” values. We do input using an I/O action that wraps a non-trivial value.

> :t getChar
getChar :: IO Char
> :t getLine
getLine :: IO String


We can bind a variable name to the wrapped value by using “<-”.

reverseIt = do
putStr "Type something: "
line <- getLine
putStr "You typed (backwards): "
putStrLn (reverse line)


Above, the name line is bound to the String wrapped by the I/O action that getLine returns. This String is read from the standard input.

Two important points:

• A name is bound to a wrapped value only in the context of a do block.
• A wrapped value cannot be removed from the “I/O world”, but it can be processed inside it (e.g., the above call to function reverse).

### Using return in a do Block

All of the above I/O actions involved a non-trivial side effect. We can wrap a value in a do-nothing side effect using return. For example, “return x” produces a do-nothing I/O action that wraps the value x. And “return ()” produces a do-nothing I/O action that wraps a “nothing” value—essentially a null I/O action.

-- myGetLine
-- Same as getLine, but showing how to write it using getChar.
myGetLine = do
c <- getChar
if c == '\n'
then return ""
else do
rest <- myGetLine
return (c:rest)


Note that each expression in a do block needs to return an I/O action. However, these expressions can be complicated. For example, from the above if to the end of the do block is a single expression.

Also note that Haskell’s “returndoes not return. It simply creates a do-nothing I/O action. There is nothing to prevent us from doing several return expressions in a row, following by—say—a putStrLn. (Try it!) However, in practice a return is almost always the last I/O action performed. Thus the name “return” makes sense.

### Using let in a do Block

One last bit of syntax remains. We can use “let ... = ...” in a do block to bind a name to a non-I/O value, for the remainder of the do block.

-- squareEm
-- Repeatedly input a number from the user. If 0, then quit; otherwise
--  print its square, and repeat.
squareEm = do
putStr "Type a number (0 to quit): "
line <- getLine    -- Bind name to I/O-wrapped value
let n = read line  -- Bind name to non-I/O value
-- Compiler knows n is a number by how it is used
if n == 0
then return () -- Must have I/O action here, so make it null
else do
putStr "Squaring, we get: "
print (n*n)
squareEm   -- repeat


Above, the “then” portion of the expression must return an I/O action; otherwise we have a type error. However, at this point we simply want to leave, so there is nothing for this I/O action to do. Thus we use return () to create a null I/O action.

### Quick Summary of Haskell I/O

• I/O is separate from string conversions.
• I/O is done by returning a value called an “I/O action” to the outside world.
• A do block combines multiple I/O actions into a single I/O action.
• An I/O action is essentially a side effect wrapping a value. Use “<-” to bind a variable name to a wrapped value, in the context of a do block.
• Use return to create a do-nothing I/O action wrapping a specified value.
• Use let inside a do block to bind a variable name to a non-I/O value.

See haskell_io.hs for Haskell source code related to today’s lecture.

CS 331 Spring 2013: Lecture Notes for Wednesday, February 27, 2013 / Updated: 27 Feb 2013 / Glenn G. Chappell / ggchappell@alaska.edu