37
Haskell: Flow of Control Haskell: I/O CS F331 Programming Languages CSCE A331 Programming Language Concepts Lecture Slides Wednesday, March 1, 2017 Glenn G. Chappell Department of Computer Science University of Alaska Fairbanks [email protected] © 2017 Glenn G. Chappell continued

Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

  • Upload
    others

  • View
    58

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: Flow of ControlHaskell: I/O

CS F331 Programming LanguagesCSCE A331 Programming Language ConceptsLecture SlidesWednesday, March 1, 2017

Glenn G. ChappellDepartment of Computer ScienceUniversity of Alaska [email protected]

© 2017 Glenn G. Chappell

continued

Page 2: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

ReviewHaskell: Functions [1/2]

Function definition: what looks like a function call, an equals sign, and an expression for the value of the function. Pattern matching is used. Introduce local definitions with where.

factorial 0 = 1factorial n = n * factorial prev where

prev = n-1

We can also define new infix binary operators.

a +$+ b = 2*a + b

1 Mar 2017 CS F331 / CSCE A331 Spring 2017

Patterns

Local definition

2

Page 3: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

ReviewHaskell: Functions [2/2]

Currying: simulating a multiparameter function using a single parameter function that returns a function.

sub a b = a-bsub 5 2 -- Returns 3sub_from_5 = sub 5sub_from_5 2 -- Returns 3

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 3

Page 4: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

ReviewHaskell: Lists [1/3]

A Haskell list holds an arbitrary number of data items, all of the same type. A list literal uses brackets and commas.

["hello", "there"] -- List of two String values[[1], [], [1,2,3,4]] -- List of lists of Integer[1, [2, 3]] -- ERROR; types differ[1, 3 ..] -- Infinite list

Haskell has three list primitives.1. Construct an empty list: []2. Cons: list from first item, list of other items: head:tail3. Pattern matching for lists.

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 4

Page 5: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

ReviewHaskell: Lists [2/3]

Haskell has list comprehensions.

> [ x*y | x <- [3, 2, 1], y <- [10, 11, 12] ][30,33,36,20,22,24,10,11,12]

> [ x*x | x <- [1..6] ][1,4,9,16,25,36]

> [ x | x <- [1..20], x `mod` 2 == 1][1,3,5,7,9,11,13,15,17,19]

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 5

Page 6: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

ReviewHaskell: Lists [3/3]

A function that takes a list will often be recursive. Such a function will usually be organized as follows.§ The version that handles the empty list ([]) will be the base case.§ The version that handles nonempty lists (b:bs) will be the recursive

case. This will do a computation involving the head of the list (b) and make a recursive call with the tail (bs).

myFilter p [] = [] -- p for predicate: function-- returning Bool

myFilter p (x:xs) = if (p x) then x:restelse rest where

rest = myFilter p xs

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 6

Page 7: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

ReviewHaskell: Flow of Control — Introduction

Flow of control refers to the ways a PL determines what code is executed. For example, flow of control in Lua includes:§ Selection (if … elseif … else).§ Iteration (while, for).§ Function calls.§ Coroutines.§ Threads.§ Exceptions.

Haskell has very different flow-of-control facilities from most imperative PLs.

Key Idea. Things that are done with traditional flow-of-control constructs in imperative programming languages are often done differently in Haskell.

1 Mar 2017 CS F331 / CSCE A331 Spring 2017

For code, see flow.hs.

7

Page 8: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

ReviewHaskell: Flow of Control — Pattern Matching, Recursion, Lazy Eval.

Haskell includes the versatile combination of pattern matching, recursion, and lazy evaluation.

Examples:

-- myIf – an if-else construct we can write ourselves.myIf True tVal _ = tValmyIf False _ fVal = fVal

-- listFrom n - returns infinite list [n, n+1, n+2, …].listFrom n = n:listFrom (n+1)

The lack of a base case is not a problem, thanks to lazy evaluation.The above code uses corecursion:

§ A stream of values is generated recursively.§ The recursion terminates when no more values are needed.

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 8

Page 9: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

ReviewHaskell: Flow of Control — Selection: Guards

Guards are the Haskell equivalent of mathematical notation like the following.

𝑚𝑦𝐴𝑏𝑠 𝑥 = (𝑥, if𝑥 ≥ 0;−𝑥, otherwise.

In Haskell:

myAbs x| x >= 0 = x| otherwise = -x

We use guards in situations that pattern matching cannot handle. For example, there is no pattern that matches only nonnegative numbers.

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 9

Page 10: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: Flow of ControlEncapsulated Loops — Introduction

Haskell allows us to encapsulate flow-of-control constructs as functions. We have already done this with myIf. We look at some functions that encapsulate loops.§ map§ filter§ zip§ Fold operations

1 Mar 2017 CS F331 / CSCE A331 Spring 2017

continued

For code, see flow.hs.

10

Page 11: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: Flow of ControlEncapsulated Loops — map & filter [1/3]

Consider the following C++ code. v is a vector<int>.

vector<int> w;for (auto n : v){

w.push_back(n % 3);}

The same computation in Haskell is done without a loop.

w = map (\ n -> n `mod` 3) vw = [ n `mod` 3 | n <- v ] -- Alternate form

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 11

Page 12: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: Flow of ControlEncapsulated Loops — map & filter [2/3]

Another C++ snippet:

vector<int> w;for (auto n : v){

if (n > 6)w.push_back(n);

}

And the equivalent Haskell:

w = filter (> 6) vw = [ n | n <- v, n > 6 ] -- Alternate form

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 12

Page 13: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: Flow of ControlEncapsulated Loops — map & filter [3/3]

So Haskell’s map and filter functions—or the equivalent list comprehensions—perform operations that we would use loops for in other PLs.

In particular, map and filter encapsulate loops that process a sequence of values, constructing another sequence of values.

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 13

Page 14: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: Flow of ControlEncapsulated Loops — zip

Haskell also has functions that encapsulate other kinds of loops. For example, zip takes two lists and returns a single list of pairs.

> zip [8,3,7] "dog"[(8,'d'),(3,'o'),(7,'g')

Function zip stops when either of the given lists runs out.

> zip [8,3,7] "doggies"[(8,'d'),(3,'o'),(7,'g')

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 14

Page 15: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: Flow of ControlEncapsulated Loops — Fold Operations [1/3]

Yet another kind of loop involves processing a sequence of values and returning a single value. The result might be the sum of all the numbers in the sequence, the greatest value in the sequence, etc. The operation performed by a loop like this is called a fold (or sometimes reduce).

Here is an example of a fold operation in C++.

int result = 0; // Will hold sum of items in vfor (auto n : v){

result += n;}

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 15

Page 16: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: Flow of ControlEncapsulated Loops — Fold Operations [2/3]

Haskell has a number of fold functions. These include foldl, foldr, foldl1, and foldr1 (the “l” and “r” stand for “left” and “right”). Below, I show a call to each function, with a comment showing what the call computes.

foldl (+) 0 [1,2,3,4] -- (((0+1)+2)+3)+4

foldr (+) 0 [1,2,3,4] -- 1+(2+(3+(4+0)))

foldl1 (+) [1,2,3,4] -- ((1+2)+3)+4

foldr1 (+) [1,2,3,4] -- 1+(2+(3+4))

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 16

Page 17: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: Flow of ControlEncapsulated Loops — Fold Operations [3/3]

Here are practical examples of Haskell folds.

> let commafy str1 str2 = str1 ++ ", " ++ str2> foldl1 commafy ["hello","there","everyone"]"hello, there, everyone"

> let bigger a b = if (b > a) then b else a> let maxVal list = foldl1 bigger list> maxVal [5,2,7,3,9,8,4,9,2,1]9

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 17

Page 18: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: Flow of Controldo Construction Preview [1/2]

A final flow-of-control structure, which we will look at when we study Haskell I/O, is the do construction. An example:

reverseIt = doputStr "Type something: "line <- getLineputStr "What you typed, reversed: "putStrLn (reverse line)

When this executes, it looks like this:

> reverseItType something: Howdy!What you typed, reversed: !ydwoH

1 Mar 2017 CS F331 / CSCE A331 Spring 2017

Typed by user

18

Page 19: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: Flow of Controldo Construction Preview [2/2]

reverseIt = doputStr "Type something: "line <- getLineputStr "What you typed, reversed: "putStrLn (reverse line)

A do construction is syntactic sugar around a pipeline of functions. Roughly, each function takes the current state and returns it, possibly modified by an I/O action. Each of the lines above, except the first line. represents an I/O action.

More on this in our next topic: Haskell I/O.

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 19

Page 20: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: I/OString Conversion — Introduction [1/2]

In many PLs, conversion to & from 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.

Some examples (n is a numeric variable):

cout << n; // C++System.out.print(n); // Javaio.write(n) -- Lua

Each of the above will first convert n to a string, and then send this string to the standard output.

1 Mar 2017 CS F331 / CSCE A331 Spring 2017

For code, see io1.hs.

20

Page 21: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: I/OString Conversion — Introduction [2/2]

Haskell, on the other hand, keeps string conversion and I/O (mostly) separate.

nstr = show n -- Convert n to a stringputStr nstr -- Print the string

putStr $ show n -- Do both

We briefly cover Haskell’s string conversion facilities. Then we look at Haskell I/O—which will require a bit more time.

1 Mar 2017 CS F331 / CSCE A331 Spring 2017

Recall: The $ operator does function application, but it is very low precedence. So this line is the same as “putStr (show n)”.

21

Page 22: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: I/OString Conversion — Type Classes [1/2]

A Haskell type class (or simply class) is a collection of types that implement a common interface.

Some common examples:§ Eq: Equality-comparable types. Every type in class Eq has the ==

and /= (inequality) operators defined.§ Ord: Orderable types. Every type in class Ord has the various

ordered comparison operators defined: <, <=, >, >=.§ Num: Numeric types. Every type in class Num has the binary +, -

and * operators, along with other things like abs (absolute value).

Haskell does overloading only via type classes. For example, the types in class Eq are the only types for which == is defined.

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 22

Page 23: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: I/OString Conversion — Type Classes [2/2]

We have seen type classes before in contexts like the following:

foo :: (Num a, Eq a) => a -> a

The above says foo is a function that takes something of type aand returns the same type, where a can be any numeric type that is equality-comparable.

Two important type classes related to string conversion:§ Show: Showable types. Every type in class Show can be converted

to String using the overloaded function show.§ Read: Readable types. Every type in class Read has conversion-

from-String using the overloaded function read.

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 23

Page 24: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: I/OString Conversion — show

To convert any showable value to a String, pass it to show.

> show 3"3"> show [True]"[True]"

Not all types are showable.

> let square x = x*x> show square

[Error]

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 24

Page 25: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: I/OString Conversion — read [1/2]

To convert a String to a readable type, pass the String to read.

> let fivestr = "5"> 2 + read fivestr7

Type annotations are sometimes needed.

> read fivestr -- Convert String to ... what?

[Error]> (read fivestr)::Integer5> (read fivestr)::Double5.0

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 25

Page 26: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: I/OString Conversion — read [2/2]

> (read fivestr)::Integer5> (read fivestr)::Double5.0

The above illustrates an interesting feature of Haskell.Both Haskell and C++ support function overloading: creating

distinct functions with the same name. In C++ we can overload only on the number and types of parameters; we must be able to choose which function to use based only on the number and types of the parameters.

But in Haskell, we can overload on the return type. There are various versions of function read; all have the same name, and all take a single String parameter. But they have different return types; Haskell can determine which to use based on this.

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 26

Page 27: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: I/OSimple Output [1/3]

I/O necessarily involves side effects: changes that are visible outside a function. But Haskell does not allow side effects.

We do I/O in Haskell as follows: the return value of a program is a description of the side effects the program would like to do. The runtime environment will perform the side effects.

A side effect description is stored as a Haskell I/O action. For example, here is function putStr.

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

Function putStr takes a String and returns an I/O action representing printing the String to the standard output.

1 Mar 2017 CS F331 / CSCE A331 Spring 2017

Return type: I/O action

27

Page 28: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: I/OSimple Output [2/3]

Entering an expression whose value is an I/O action at the GHCiprompt, results in the I/O being performed.

> putStrLn "Hello!"Hello!> putStrLn $ show $ map (\ x -> x*x) [1, 2, 3][1,4,9]

In a complete program, an I/O action can be returned by main. Here is a Haskell hello-world program.

main = putStrLn "Hello, world!"

1 Mar 2017 CS F331 / CSCE A331 Spring 2017

Like putStr, but add a newline at the end of the given String.

28

Page 29: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: I/OSimple Output [3/3]

Combine multiple I/O actions into a single I/O action using the >>operator.

> putStr "Hello" >> putStrLn " there!"Hello there!> putStr "dog" >> putStrLn "mouse" >> putStrLn "boat"dogmouseboat> putStr "I have " >> putStr (show (73*94+22))

>> putStrLn " hamsters."I have 6884 hamsters.

1 Mar 2017 CS F331 / CSCE A331 Spring 2017

We will eventually discuss a nicer way to combine I/O actions. But when we use it, this is what is

going on under the hood.

29

Page 30: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: I/OSimple Input [1/5]

The full story on I/O actions is that an I/O action represents:§ a description of a sequence of side effects, and§ a wrapped value.

Recall the “()” in the type of putStr.

putStr :: String -> IO ()

“()” means that the I/O action returned by putStr wraps a “nothing” value.

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 30

Page 31: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: I/OSimple Input [2/5]

When we do input, we use an I/O action that wraps the value we are inputting.

> :t getLinegetLine :: IO String

getLine returns an I/O action that inputs a line of text from the standard input. The wrapped value is a String representing the line of text (without the ending newline).

Now, how do we access the wrapped String?

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 31

Page 32: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: I/OSimple Input [3/5]

Using the >>= operator, we can combine§ an I/O action wrapping a value, and§ a function that takes such a value and returns an I/O action.

The wrapped value is passed to the function.The result is an I/O action that includes the side effects of both the

original I/O action and the one returned by the function. The value it wraps is that wrapped by the I/O action returned by the function.

1 Mar 2017 CS F331 / CSCE A331 Spring 2017

I/O ActionValue Function I/O

ActionValueThe >>= operator passes the wrapped value …

… to the given function.

Result: an I/O action including the side effects of both of these, wrapping whatever value the second I/O action wraps.

32

Page 33: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: I/OSimple Input [4/5]

For example, getLine returns an I/O action wrapping a String. Function putStrLn takes a String and returns an I/O action.

> getLine >>= putStrLnHowdy!Howdy!

1 Mar 2017 CS F331 / CSCE A331 Spring 2017

Typed by user

I/O ActionValue Function I/O

ActionValueThe >>= operator passes the wrapped value …

… to the given function.

Result: an I/O action including the side effects of both of these, wrapping whatever value the second I/O action wraps.

33

Page 34: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: I/OSimple Input [5/5]

I/O actions involving multiple side effects work, too.

> (putStr "Type something: " >> getLine) >>= putStrLnType something: I like hamsters!I like hamsters!

We can give the parameter of putStrLn a name:

> getLine >>= (\ line -> putStrLn line)Hamsters rule ...Hamsters rule ...> getLine >>= (\ line -> putStrLn (reverse line))... this planet and others like it..ti ekil srehto dna tenalp siht ...

1 Mar 2017 CS F331 / CSCE A331 Spring 2017

Next:the “nicer way”.

Same as putStrLn(right?)

Parentheses are actually unnecessary. The operators have equal precedence and are both left-associative.

34

Page 35: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: I/Odo Construction [1/2]

Haskell’s do construction offers a less messy way to write I/O.The keyword do is followed by an indented block. I/O actions in the

block are combined into a single I/O action. Internally, this is done using the >> and >>= operators.

Using operators:putStr s >> putStrLn t

Using a do construction:do

putStr sputStrLn t

1 Mar 2017 CS F331 / CSCE A331 Spring 2017

Using operators:getLine >>=

(\ line -> putStrLn line)

Using a do construction:do

line <- getLineputStrLn line

35

Variable linecan be used in the rest of the do block.

Page 36: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: I/Odo Construction [2/2]

Here is a Haskell program that prompts the user for a line of text and then prints the length of the line and the line itself, backwards.

main = doputStr "Type some text: "line <- getLineputStrLn ""putStrLn $ "Line length: " ++ show (length line)putStrLn ""putStr "Here is your text, backwards: "putStrLn $ reverse line

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 36

Page 37: Haskell: Flow of Control continued Haskell: I/Ochappell/class/2017_spr/... · Haskell: Flow of Control —Pattern Matching, Recursion, Lazy Eval. Haskell includes the versatile combination

Haskell: I/OTO BE CONTINUED …

Haskell: I/O will be continued next time.

1 Mar 2017 CS F331 / CSCE A331 Spring 2017 37