Introduction to Haskell

Similar documents
CS 11 Haskell track: lecture 1

An introduction to functional programming. July 23, 2010

Programming Paradigms

Monad Background (3A) Young Won Lim 11/18/17

Monad Background (3A) Young Won Lim 11/8/17

Haskell Introduction Lists Other Structures Data Structures. Haskell Introduction. Mark Snyder

Programming in Haskell Aug Nov 2015

n n Try tutorial on front page to get started! n spring13/ n Stack Overflow!

Solution sheet 1. Introduction. Exercise 1 - Types of values. Exercise 2 - Constructors

Side Effects (3B) Young Won Lim 11/23/17

Side Effects (3B) Young Won Lim 11/20/17

Side Effects (3B) Young Won Lim 11/27/17

CS 360: Programming Languages Lecture 10: Introduction to Haskell

Background Operators (1E) Young Won Lim 7/7/18

An introduction introduction to functional functional programming programming using usin Haskell

Haske k ll An introduction to Functional functional programming using Haskell Purely Lazy Example: QuickSort in Java Example: QuickSort in Haskell

Monad Background (3A) Young Won Lim 10/5/17

Practical Haskell. An introduction to functional programming. July 21, Practical Haskell. Juan Pedro Villa-Isaza. Introduction.

Advanced Topics in Programming Languages Lecture 2 - Introduction to Haskell

Informatics 1 Functional Programming Lectures 15 and 16. IO and Monads. Don Sannella University of Edinburgh

The List Datatype. CSc 372. Comparative Programming Languages. 6 : Haskell Lists. Department of Computer Science University of Arizona

INTRODUCTION TO FUNCTIONAL PROGRAMMING

Programming Languages Fall 2013

CMSC 330: Organization of Programming Languages. Functional Programming with Lists

Standard prelude. Appendix A. A.1 Classes

I/O in Purely Functional Languages. Stream-Based I/O. Continuation-Based I/O. Monads

CS 440: Programming Languages and Translators, Spring 2019 Mon 2/4

CS 360: Programming Languages Lecture 12: More Haskell

CSCI-GA Scripting Languages

Functional Programming for Logicians - Lecture 1

CS 457/557: Functional Languages

Background Type Classes (1B) Young Won Lim 6/28/18

Haskell 101. (Version 1 (July 18, 2012)) Juan Pedro Villa Isaza

CSCE 314 Programming Languages. Interactive Programming: I/O

Informatics 1 Functional Programming 19 Tuesday 23 November IO and Monads. Philip Wadler University of Edinburgh

CMSC 330: Organization of Programming Languages. Functional Programming with Lists

Side Effects (3A) Young Won Lim 1/13/18

IO Monad (3C) Young Won Lim 1/6/18

Haskell Syntax in Functions

PROGRAMMING IN HASKELL. Chapter 10 - Interactive Programming

Programming with Math and Logic

Overloading, Type Classes, and Algebraic Datatypes

Haskell: From Basic to Advanced. Part 2 Type Classes, Laziness, IO, Modules

CSCE 314 TAMU Fall CSCE 314: Programming Languages Dr. Flemming Andersen. Haskell Functions

Haskell Monads CSC 131. Kim Bruce

IO Monad (3D) Young Won Lim 1/18/18

Haskell Making Our Own Types and Typeclasses

Haskell An Introduction

According to Larry Wall (designer of PERL): a language by geniuses! for geniuses. Lecture 7: Haskell. Haskell 98. Haskell (cont) - Type-safe!

CSC312 Principles of Programming Languages : Functional Programming Language. Copyright 2006 The McGraw-Hill Companies, Inc.

EECS 700 Functional Programming

IO Monad (3C) Young Won Lim 8/23/17

CS457/557 Functional Languages

PROGRAMMING IN HASKELL. CS Chapter 6 - Recursive Functions

INTRODUCTION TO HASKELL

Haskell: Lists. CS F331 Programming Languages CSCE A331 Programming Language Concepts Lecture Slides Friday, February 24, Glenn G.

Parallel Haskell on MultiCores and Clusters

Parsing. Zhenjiang Hu. May 31, June 7, June 14, All Right Reserved. National Institute of Informatics

CS 320: Concepts of Programming Languages

PROGRAMMING IN HASKELL. Chapter 2 - First Steps

GHCi: Getting started (1A) Young Won Lim 6/3/17

Lecture 19: Functions, Types and Data Structures in Haskell

1. true / false By a compiler we mean a program that translates to code that will run natively on some machine.

CSCE 314 Programming Languages

CS 209 Functional Programming

Lazy Functional Programming in Haskell

Haskell Types, Classes, and Functions, Currying, and Polymorphism

This example highlights the difference between imperative and functional programming. The imperative programming solution is based on an accumulator

Functional Programming and Haskell

A Second Look At ML. Chapter Seven Modern Programming Languages, 2nd ed. 1

Haskell through HUGS THE BASICS

Programming in Haskell Aug-Nov 2015

Fall 2017 Discussion 7: October 25, 2017 Solutions. 1 Introduction. 2 Primitives

Haskell & functional programming, some slightly more advanced stuff. Matteo Pradella

Summer 2017 Discussion 10: July 25, Introduction. 2 Primitives and Define

CS 457/557: Functional Languages

Functional Logic Programming Language Curry

Introduction to OCaml

SCHEME 7. 1 Introduction. 2 Primitives COMPUTER SCIENCE 61A. October 29, 2015

References. Monadic I/O in Haskell. Digression, continued. Digression: Creating stand-alone Haskell Programs

Lecture 8: Summary of Haskell course + Type Level Programming

CS 320: Concepts of Programming Languages

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages

CIS552: Advanced Programming

CSc 372. Comparative Programming Languages. 8 : Haskell Function Examples. Department of Computer Science University of Arizona

CSc 372. Comparative Programming Languages. 3 : Haskell Introduction. Department of Computer Science University of Arizona

Course year Typeclasses and their instances

CIS 194: Homework 3. Due Wednesday, February 11, Interpreters. Meet SImPL

Spring 2018 Discussion 7: March 21, Introduction. 2 Primitives

Box-and-arrow Diagrams

CPL 2016, week 10. Clojure functional core. Oleg Batrashev. April 11, Institute of Computer Science, Tartu, Estonia

7. Introduction to Denotational Semantics. Oscar Nierstrasz

CS 457/557: Functional Languages

It is better to have 100 functions operate one one data structure, than 10 functions on 10 data structures. A. Perlis

Haskell 98 in short! CPSC 449 Principles of Programming Languages

I/O in Haskell. To output a character: putchar :: Char -> IO () e.g., putchar c. To output a string: putstr :: String -> IO () e.g.

FUNCTIONAL PROGRAMMING 1 HASKELL BASICS

Haskell Overview II (2A) Young Won Lim 8/9/16

Monad Background (3A) Young Won Lim 11/20/17

Haskell A Wild Ride. Abstract. 1 Safety Precautions. Sven Moritz Hallberg

Transcription:

Introduction to Haskell Matt Mullins Texas A&M Computing Society October 6, 2009 Matt Mullins (TACS) Introduction to Haskell October 6, 2009 1 / 39

Outline Introduction to Haskell Functional Programming Haskell Specifics Beginning Haskell Using Haskell First Bits of Syntax Slightly More Advanced Types A Real Haskell Program Core Logic Monads The Parser Bringing it all together Matt Mullins (TACS) Introduction to Haskell October 6, 2009 2 / 39

Outline Introduction to Haskell Introduction to Haskell Functional Programming Haskell Specifics Beginning Haskell Using Haskell First Bits of Syntax Slightly More Advanced Types A Real Haskell Program Core Logic Monads The Parser Bringing it all together Matt Mullins (TACS) Introduction to Haskell October 6, 2009 3 / 39

Introduction to Haskell What is functional programming? Functional Programming Instead of a series of modifications, functional programming uses immutable data. Variables contents never change Matt Mullins (TACS) Introduction to Haskell October 6, 2009 4 / 39

Introduction to Haskell What is functional programming? Functional Programming Instead of a series of modifications, functional programming uses immutable data. Variables contents never change Functions (i.e. pure functions) always return the same result when given the same input. There is no state when using pure functions the only state information is the function arguments. This is a more mathematical use of the word function, but it is still extremely usable for computer programs. Matt Mullins (TACS) Introduction to Haskell October 6, 2009 4 / 39

Introduction to Haskell Functional Programming Why should I use it? Easier to test, prevent bugs, etc Easier to prove correctness Haskell uses lazy evaluation: expressions are evaluated only when necessary, allowing data structures like the infinite list. Estimating theoretical performance can be easy, because you can use the mathematical definitions Can still use non-functional programming constructions more on that later Matt Mullins (TACS) Introduction to Haskell October 6, 2009 5 / 39

Why should I use it? Introduction to Haskell Functional Programming Easier to test, prevent bugs, etc Easier to prove correctness Haskell uses lazy evaluation: expressions are evaluated only when necessary, allowing data structures like the infinite list. Estimating theoretical performance can be easy, because you can use the mathematical definitions Can still use non-functional programming constructions more on that later Can theoretically be automatically made concurrent by the compiler Useful now that dual- and quad-core computers are common Still a subject of research: the functionality is nowhere near complete. It still probably won t help you. Matt Mullins (TACS) Introduction to Haskell October 6, 2009 5 / 39

Why shouldn t I use it? Introduction to Haskell Functional Programming Somewhat difficult to debug, since you can t step through code Lazy evaluation means your code isn t always evaluated in the same order. Can be hard to read someone else s code Estimating real performance can be difficult Some APIs don t have bindings for Haskell yet Matt Mullins (TACS) Introduction to Haskell October 6, 2009 6 / 39

Introduction to Haskell Haskell Specifics What sets Haskell apart (from other functional languages)? Main difference: everything is purely functional. Other functional languages like Scheme and OCaml allow you to modify variables after all. Lazy evaluation is impossible. Don t be scared. You can still do things that seem non-functional. Monads make this possible. Haskell is strongly-typed. Haskell has a well-designed module system, much like many newer languages such as Python and C#. Matt Mullins (TACS) Introduction to Haskell October 6, 2009 7 / 39

Outline Beginning Haskell Introduction to Haskell Functional Programming Haskell Specifics Beginning Haskell Using Haskell First Bits of Syntax Slightly More Advanced Types A Real Haskell Program Core Logic Monads The Parser Bringing it all together Matt Mullins (TACS) Introduction to Haskell October 6, 2009 8 / 39

Running the code Beginning Haskell Using Haskell Haskell code can be compiled or interpreted. Compiler: ghc Glasgow Haskell Compiler Interpreter: ghci or hugs Matt Mullins (TACS) Introduction to Haskell October 6, 2009 9 / 39

Running the code Beginning Haskell Using Haskell Haskell code can be compiled or interpreted. Compiler: ghc Glasgow Haskell Compiler Interpreter: ghci or hugs In this presentation: Lines that begin with Prelude> are the ghci interpreter Everything else would be put into a source code file. Matt Mullins (TACS) Introduction to Haskell October 6, 2009 9 / 39

Beginning Haskell First Bits of Syntax Variables and functions Variable definition uses the = operator. Prelude> let a = 3 Prelude> a 3 The let keyword is used only with the interpreter. Matt Mullins (TACS) Introduction to Haskell October 6, 2009 10 / 39

Beginning Haskell First Bits of Syntax Variables and functions Variable definition uses the = operator. Prelude> let a = 3 Prelude> a 3 The let keyword is used only with the interpreter. Function application is a space, instead of parentheses. Prelude> let f x = x+5 Prelude> f 39 44 Matt Mullins (TACS) Introduction to Haskell October 6, 2009 10 / 39

Beginning Haskell First Bits of Syntax Functions with multiple parameters Very similar construction: Prelude> let g x y z = x+y-z Prelude> g 3 4 5 2 How on earth can this work? Matt Mullins (TACS) Introduction to Haskell October 6, 2009 11 / 39

Beginning Haskell First Bits of Syntax Functions with multiple parameters Very similar construction: Prelude> let g x y z = x+y-z Prelude> g 3 4 5 2 How on earth can this work? Functions are just as much values as anything else (like a number, for instance). Function application is an operator that binds more tightly than any other. It always takes exactly one parameter, and returns another function with one fewer parameter. It is left-associative. That is: f a b c ((f a) b) c Matt Mullins (TACS) Introduction to Haskell October 6, 2009 11 / 39

Beginning Haskell Slightly More Advanced Scope Very important, similar to structured languages like C++. What happens if: Prelude> let a = 1; b = 2 Prelude> let h a b = a+b Prelude> h 5 6 Matt Mullins (TACS) Introduction to Haskell October 6, 2009 12 / 39

Beginning Haskell Slightly More Advanced Scope Very important, similar to structured languages like C++. What happens if: Prelude> let a = 1; b = 2 Prelude> let h a b = a+b Prelude> h 5 6 The answer is 11, not 3. The a and b in the function refer to its arguments, not the ones already defined. Matt Mullins (TACS) Introduction to Haskell October 6, 2009 12 / 39

Beginning Haskell Slightly More Advanced Operators Infix operators are treated simply as functions. For example, (+) is simply a function that takes two numbers and returns the sum. Parentheses are important: they make an infix operator behave like a function name. You can make up your own operators, as long as they use only the following:!#$%&*+./<=>?@\^ -~ Matt Mullins (TACS) Introduction to Haskell October 6, 2009 13 / 39

Beginning Haskell Slightly More Advanced Pattern matching When you define a function, the left side is really a pattern that the compiler matches against. Variable names match anything, and their contents are available on the right side. Constructors and literals must match exactly. Patterns are matched top-to-bottom, until a match succeeds. Example: matching a list: count [] = 0 count (x:xs) = 1 + count xs Matt Mullins (TACS) Introduction to Haskell October 6, 2009 14 / 39

Various operators Beginning Haskell Slightly More Advanced Function composition: (.) :: (a->b) -> (c->a) -> c -> b (f. g) x f (g x) Function application: ($) :: (a->b) -> a -> b Why are these used? Matt Mullins (TACS) Introduction to Haskell October 6, 2009 15 / 39

Beginning Haskell Slightly More Advanced Unnamed functions Two main ways to do it: Lambda expressions: (\x -> x+3) Half-evaluated function (or operators): g 1 2 (3+) Matt Mullins (TACS) Introduction to Haskell October 6, 2009 16 / 39

Beginning Haskell Types Haskell type system Every expression in Haskell has an unambiguous type. You can explore the type of an expression using the :t interpreter command: Prelude> :t a a :: Integer Prelude> :t g g :: (Num a) => a -> a -> a -> a Most types are inferred from context (or syntax) A type doesn t have to be unique. :: is used to express the type of a particular expression. Matt Mullins (TACS) Introduction to Haskell October 6, 2009 17 / 39

Beginning Haskell Types Lists An element cons-ed with the rest of the list The cons operator is :, and the empty list is [], so 1:(2:(3:[])) is a list 1,2,3. : is right-associative, so the above is equivalent to 1:2:3:[]. There is syntactic sugar that does this for you; it is also equivalent to [1,2,3] A list can be as long as you want, but all the elements have to be of the same type. A type specification would look like [1,2,3] :: [Integer] Matt Mullins (TACS) Introduction to Haskell October 6, 2009 18 / 39

Beginning Haskell Types Tuples A tuple is a fixed-length collection of elements that can be treated as a single object. A tuple uses the syntax (1,2), which can be used in more complicated ways, like (1,2,(3, a )) A tuple can have elements of different types, unlike a list. The type specification looks like (1,2,(3, a )) :: (Integer, Integer, (Integer, Char)) Matt Mullins (TACS) Introduction to Haskell October 6, 2009 19 / 39

Defining your own types Beginning Haskell Types data IntList = IntItem Integer IntEnd Defines two constructors : IntItem :: Integer -> IntList and IntEnd :: IntList Types can have parameters like functions: data List a = Item a End This defines two constructors: Item :: a -> List a and End :: List a Note that End is simultaneously of an infinite number of types. Matt Mullins (TACS) Introduction to Haskell October 6, 2009 20 / 39

Defining your own types Beginning Haskell Types data IntList = IntItem Integer IntEnd Defines two constructors : IntItem :: Integer -> IntList and IntEnd :: IntList Types can have parameters like functions: data List a = Item a End This defines two constructors: Item :: a -> List a and End :: List a Note that End is simultaneously of an infinite number of types. You can also define type synonyms: type OtherList = List Char Matt Mullins (TACS) Introduction to Haskell October 6, 2009 20 / 39

Type classes Beginning Haskell Types A type class is a set of types that support the same operations. We ve already seen one type class already: Num. Other important classes are: Show: function show :: (Show a) => a -> String Eq: operator (==) :: (Eq a) => a -> a -> Bool Ord: supports operations to determine ordering (i.e. <, >, etc.) Allows for polymorphism. Matt Mullins (TACS) Introduction to Haskell October 6, 2009 21 / 39

Outline A Real Haskell Program Introduction to Haskell Functional Programming Haskell Specifics Beginning Haskell Using Haskell First Bits of Syntax Slightly More Advanced Types A Real Haskell Program Core Logic Monads The Parser Bringing it all together Matt Mullins (TACS) Introduction to Haskell October 6, 2009 22 / 39

A Real Haskell Program A course scheduler As course registration time nears, I want a program which can determine the schedule that is most ideal for me. My requirements: Large contiguous blocks of time outside of class Accepts input in a format that is easy to type and read Why I chose Haskell: The ability to derive new data types with minimal code Extremely easy to define a parser for a domain-specific language I tried it in C++ first, and the only algorithm I could come up with was recursive much easier to express in Haskell. Matt Mullins (TACS) Introduction to Haskell October 6, 2009 23 / 39

The data file format A Real Haskell Program Something easy to type into a text file; example: CPSC 221{ 501{ MWF 11:30 12:20 HRBB 124; TR 15:55 16:45 HRBB 232; } 502{ MWF 11:30 12:20 HRBB 124; MW 12:40 13:30 HRBB 232; } } ENGL 301{ 570{MWF 13:50 14:40 BLOC 114; } } Matt Mullins (TACS) Introduction to Haskell October 6, 2009 24 / 39

A Real Haskell Program The core data structures Core Logic data Weekday = M T W R F deriving (Eq, Ord, Show) data Period = Period { day :: Weekday, start, end :: Time } deriving (Eq, Ord) data Section = Section { course :: Course, number :: Int, periods :: [Period] } deriving Eq data Course = Course { desig :: String, sections :: [Section] } deriving (Eq, Show) Matt Mullins (TACS) Introduction to Haskell October 6, 2009 25 / 39

A Real Haskell Program Determining overlapping periods Core Logic overlap1 :: Period -> Period -> Bool overlap1 p q = (start p >= start q && start p <= end q) (end p >= start q && end p <= end q) overlap :: Period -> Period -> Bool overlap p q = (day p == day q) && (overlap1 p q overlap1 q p) Matt Mullins (TACS) Introduction to Haskell October 6, 2009 26 / 39

A Real Haskell Program Determining conflicting sections Core Logic conflp :: [Period] -> [Period] -> Bool conflp (x:xs) ys = any (overlap x) ys conflp xs ys conflp [] _ = False conflicts :: Section -> Section -> Bool conflicts a b = conflp (periods a) (periods b) conflict :: [Section] -> Bool conflict (s:ss) = any (conflicts s) ss conflict ss conflict [] = False Matt Mullins (TACS) Introduction to Haskell October 6, 2009 27 / 39

A Real Haskell Program Core Logic Choosing one section from each class choosells :: [[Section]] -> [[Section]] choosells (c:cs) = concat [map (x:) $ choosells cs x <- c] choosells [] = [[]] choosells takes its input as one list element per course, and its output is one list element per possible schedule. Matt Mullins (TACS) Introduction to Haskell October 6, 2009 28 / 39

A Real Haskell Program Core Logic Choosing one section from each class choosells :: [[Section]] -> [[Section]] choosells (c:cs) = concat [map (x:) $ choosells cs x <- c] choosells [] = [[]] choosells takes its input as one list element per course, and its output is one list element per possible schedule. choose :: [Course] -> [[Section]] choose cs = choosells (map sections cs) Matt Mullins (TACS) Introduction to Haskell October 6, 2009 28 / 39

A Real Haskell Program Which schedule is the best? Core Logic score ps = let byday = [filter ((d==). day) ps d <- [M,T,W,R,F]] time [] = 0 time l = fromintegral $ (end $ last l) - (start $ head l) times = map time byday :: [Float] meantime = (sum times) / 5.0 in sum $ map (\x -> (x-meantime)^2) times This is the variance of the length of each day. Matt Mullins (TACS) Introduction to Haskell October 6, 2009 29 / 39

A Real Haskell Program Monads What is a Monad? A monad is some type M that supports the two operations: Promoting an expression: return :: a -> M a Combining monads: (>>=) :: M a -> (a->m b) -> M b. Note that a monadic type must have a single type argument. There is no function (in the general case) to unbox a monad. The way in which the (>>=) operator combines monads is defined by the individual monad. Matt Mullins (TACS) Introduction to Haskell October 6, 2009 30 / 39

A Real Haskell Program Monads What is a Monad? A monad is some type M that supports the two operations: Promoting an expression: return :: a -> M a Combining monads: (>>=) :: M a -> (a->m b) -> M b. Note that a monadic type must have a single type argument. There is no function (in the general case) to unbox a monad. The way in which the (>>=) operator combines monads is defined by the individual monad. Allows for stateful computation in a purely functional world. Began life as an abuse of the Haskell type system, and quickly gained status as one of its most distinctive features. Matt Mullins (TACS) Introduction to Haskell October 6, 2009 30 / 39

The IO Monad A Real Haskell Program Monads The type IO a represents an action whose value is of type a. The combination operator performs the actions in sequence. Useful functions: putstr :: String -> IO () putstrln :: String -> IO () getchar :: IO Char getline :: IO String getcontents :: IO String Matt Mullins (TACS) Introduction to Haskell October 6, 2009 31 / 39

A Real Haskell Program Monads The Parser Monad From the parsec library The type GenParser tok st val represents a parser which turns [tok] into something of type val Usually use a Parser GenParser Char () Combination operator creates a parser that matches in sequence You can break out of a Parser, but only in a purely functional way: parse :: GenParser tok () a -> String -> [tok] -> a Matt Mullins (TACS) Introduction to Haskell October 6, 2009 32 / 39

do syntax A Real Haskell Program Monads do s <- getline putstr "Hello, " putstrln s is syntactic sugar for getline >>= (\s -> putstr "Hello, " >> putstrln s) Matt Mullins (TACS) Introduction to Haskell October 6, 2009 33 / 39

do syntax A Real Haskell Program Monads do s <- getline putstr "Hello, " putstrln s is syntactic sugar for getline >>= (\s -> putstr "Hello, " >> putstrln s) With this syntax, you can almost forget it s purely functional Matt Mullins (TACS) Introduction to Haskell October 6, 2009 33 / 39

The small bits A Real Haskell Program The Parser time = do hour <- many1 digit char : minute <- many1 digit return (t (strtoint hour) (strtoint minute)) period = do date <- many1 $ oneof [ M, T, W, R, F ] spaces start <- time spaces end <- time spaces char ; spaces return [Period (chartoweekday d) start end d <- date] Matt Mullins (TACS) Introduction to Haskell October 6, 2009 34 / 39

Match a section A Real Haskell Program The Parser sectionnumber = many1 (digit) >>= return. stringtoint section = do num <- sectionnumber spaces char { spaces periods <- many1 period spaces char } spaces return (num, concat periods) Matt Mullins (TACS) Introduction to Haskell October 6, 2009 35 / 39

And now a course A Real Haskell Program The Parser coursep = do name <- coursename char { spaces sections <- many1 section spaces char } spaces (let c = Course name s s = [Section c n p (n,p) <- sections] in return c) courses = many1 coursep Matt Mullins (TACS) Introduction to Haskell October 6, 2009 36 / 39

Sorry A Real Haskell Program The Parser Sorry, guys, that huge block of code was boring. My apologies. It was easy to write, though, which is why I used Haskell Matt Mullins (TACS) Introduction to Haskell October 6, 2009 37 / 39

Output function A Real Haskell Program Bringing it all together putsingle :: [Section] -> IO () putsingle [] = putstrln "" putsingle (s:ss) = do putstr (show s) putsingle ss putsched :: [(Score, [Section])] -> IO () putsched [] = putstrln "" putsched ((sc,s):ss) = do putstr (show sc) putstr "\t" putsingle s putsched ss Matt Mullins (TACS) Introduction to Haskell October 6, 2009 38 / 39

The main expression A Real Haskell Program Bringing it all together scoresched :: [Section] -> Int scoresched x = score. sort. concat. map periods $ x dowork :: [Course] -> IO () dowork cs = let sch = schedule cs ss = map (\s -> (scoresched s, s)) sch sed = sortby (comparing fst) ss in putsched sed main = do s <- getcontents (case parse courses "stdin" s of (Right cs) -> dowork cs (Left cs) -> print cs) Matt Mullins (TACS) Introduction to Haskell October 6, 2009 39 / 39