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

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

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

Programming in Haskell Aug Nov 2015

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

PROGRAMMING IN HASKELL. Chapter 10 - Interactive Programming

INTERACTION FUNCTIONS

Introduction to Haskell

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

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

Programming Languages

Haskell Monads CSC 131. Kim Bruce

CSCE 314 Programming Languages. Interactive Programming: I/O

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

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

Using Monads for Input and Output

CS The IO Monad. Slides from John Mitchell, K Fisher, and S. Peyton Jones

Standard prelude. Appendix A. A.1 Classes

CS 457/557: Functional Languages

CS 11 Haskell track: lecture 1

Haskell. COS 326 Andrew W. Appel Princeton University. a lazy, purely functional language. slides copyright David Walker and Andrew W.

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

More on functional programming

M-Structures (Continued)

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

Advanced Programming Handout 7. Monads and Friends (SOE Chapter 18)

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

COMP3151/9151 Foundations of Concurrency Lecture 8

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

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

A lexical analyzer generator for Standard ML. Version 1.6.0, October 1994

Monad P1 : Several Monad Types (4A) Young Won Lim 2/13/19

Programming Paradigms

CS1622. Semantic Analysis. The Compiler So Far. Lecture 15 Semantic Analysis. How to build symbol tables How to use them to find

Parallel Haskell on MultiCores and Clusters

Functional Logic Programming Language Curry

CS52 - Assignment 8. Due Friday 4/15 at 5:00pm.

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

Monad (1A) Young Won Lim 6/9/17

Monads. Functional Programming (CS4011) Monads

HASKELL I/O. Curt Clifton Rose-Hulman Institute of Technology. Please SVN Update your HaskellInClass folder, then open eieio.hs

Monad (3A) Young Won Lim 8/9/17

step is to see how C++ implements type polymorphism, and this Exploration starts you on that journey.

CIS 252 Introduction to Computer Science Section M013: Exam 3 (Blue) April 26, Points Possible

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

Lecture 19: Functions, Types and Data Structures in Haskell

Monad class. Example: Lambda laughter. The functional IO problem. EDAN40: Functional Programming Functors and Monads

An introduction introduction to functional functional programming programming using usin Haskell


All the operations used in the expression are over integers. a takes a pair as argument. (a pair is also a tuple, or more specifically, a 2-tuple)

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

CS457/557 Functional Languages

Defining Functions. CSc 372. Comparative Programming Languages. 5 : Haskell Function Definitions. Department of Computer Science University of Arizona

8. Characters, Strings and Files

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

IO and Instructions. Original by Koen Claessen

LECTURE 16. Functional Programming

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

CS113: Lecture 7. Topics: The C Preprocessor. I/O, Streams, Files

The role of semantic analysis in a compiler

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

CSc 372. Comparative Programming Languages. 13 : Haskell Lazy Evaluation. Department of Computer Science University of Arizona

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

Overview. Declarative Languages. General monads. The old IO monad. Sequencing operator example. Sequencing operator

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

CSE341 Autumn 2017, Final Examination December 12, 2017

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

Maybe Monad (3B) Young Won Lim 12/21/17

G Programming Languages - Fall 2012

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

CS422 - Programming Language Design

Monad (1A) Young Won Lim 6/21/17

Principles of Programming Languages

Monad (1A) Young Won Lim 6/26/17

File Access. FILE * fopen(const char *name, const char * mode);

Types and Static Type Checking (Introducing Micro-Haskell)

CSE 505: Concepts of Programming Languages

COP4020 Programming Languages. Functional Programming Prof. Robert van Engelen

Starting to Program in C++ (Basics & I/O)

File IO and command line input CSE 2451

Divisibility Rules and Their Explanations

Semantic Analysis. Outline. The role of semantic analysis in a compiler. Scope. Types. Where we are. The Compiler Front-End

Functional Programming Languages (FPL)

Composable Shared Memory Transactions Lecture 20-2

INTRODUCTION TO HASKELL

for (i=1; i<=100000; i++) { x = sqrt (y); // square root function cout << x+i << endl; }

INTRODUCTION TO FUNCTIONAL PROGRAMMING

Systems Programming. 08. Standard I/O Library. Alexander Holupirek

Advanced Topics in Programming Languages Lecture 2 - Introduction to Haskell

The type checker will complain that the two branches have different types, one is string and the other is int

CS558 Programming Languages

Haskell: yet another Functional Language. Distributed and Parallel Technology

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

for (i=1; i<=100000; i++) { x = sqrt (y); // square root function cout << x+i << endl; }

cs173: Programming Languages Midterm Exam

Monad Overview (3B) Young Won Lim 1/16/18

CSE341: Programming Languages Lecture 9 Function-Closure Idioms. Dan Grossman Winter 2013

These notes are intended exclusively for the personal usage of the students of CS352 at Cal Poly Pomona. Any other usage is prohibited without

Principles of Programming Languages, 3

A Simple Syntax-Directed Translator

Intro. Scheme Basics. scm> 5 5. scm>

Transcription:

I/O in Purely Functional Languages Stream-Based I/O Four centuries ago, Descartes pondered the mind-body problem: how can incorporeal minds interact with physical bodies? Designers of purely declarative languages (such as Haskell) face an analogous problem: how can virtual software interact with the physical world? Or using fewer $0.25 words: how can you do input/output in a purely functional language? If the computation consists of just applying a function to an argument and getting the result this is easy. But what if you want interaction? Three main techniques: stream-based I/O continuation-based I/O monads The input and output are both (potentially infinite) streams of characters. This works OK if input and output aren t interleaved... but due to lazy evaluation for more complex interactive programs it becomes difficult to predict the program s behavior. Example (from Miranda). In Miranda the value of a command level expression is a list of `system messages. The system `prints such a list of messages by reading it in order from left to right, evaluating and obeying each message in turn as it is encountered. sys_message ::= Stdout [char] Stderr [char] Tofile [char] [char] Closefile [char] Appendfile [char] System [char] Exit num Stdout, for example, causes its string argument to be printed to standard out. Alan Borning 1 CSE 505 Alan Borning 2 CSE 505 Continuation-Based I/O Example from the previous version of Haskell: write a file, read it back in, and compare the contents s1 = this is a test... main = writefile ReadMe s1 exit ( readfile ReadMe exit (\s2-> appendchan stdout (if s1==s2 then contents match else something intervened! ) exit done)) type Name = String type StrCont = String -> Dialog writefile :: Name -> String -> FailCont -> SuccCont -> Dialog readfile :: Name -> FailCont -> StrCont -> Dialog appendchan :: Name -> String -> FailCont -> SuccCont -> Dialog done :: Dialog exit :: FailCont (FailCont is the type failure continuation) Monads The current preferred solution to Haskell s mind-body problem. Based on some mathematically intense ideas from category theory. Exposition mostly stolen from Phil Wadler s paper in Sept 1997 ACM Computing Surveys. IO ( ): the type of simple commands. ( ) is the unit type, like void in C++ A term of type IO ( ) denotes an action, but does not necessarily perform the action. Function to print a character: putchar :: Char -> IO () Thus putchar! denotes the action that, if it is ever performed, will print an exclamation. done :: IO ( ) Thus done denotes the action that, if it is ever performed, will do nothing (done is not built in -- we ll define it shortly). Alan Borning 3 CSE 505 Alan Borning 4 CSE 505

More Monads >> is a function to combine monads. If m and n are commands, then m>>n is the command that, if it is ever performed, will do m and then n. (>>) :: IO () -> IO () -> IO () (Actually >> has a more general type in Haskell 98, but let s use this for now.) We can now define a function puts to put a string: puts :: String -> IO () puts [] = done puts (c:s) = putc c >> puts s Therefore puts hi is equivalent to putc h >> (putc i >> done) puts hi is thus the command that, if it is ever performed, will print hi Performing Commands But, you cry, how does anything ever actually happen?? 1) We can have a distinguished top-level variable main with the following type main :: IO () When we use runhugs (rather than hugs ) the command main will be run. main = puts haskell lives! (If you want to try this, it is in the file ~borning/hasell/hello.hs on ceylon.) 2) We can start Haskell as usual using hugs. We define any variable as a command, then invoke it. In a file: test = puts haskell lives! then invoke it using test Alan Borning 5 CSE 505 Alan Borning 6 CSE 505 Monads and Equational Reasoning: ML Monads and Equational Reasoning: ML (2) Consider the following ML expression. (ML is a mostly-functional programming language, but with call-by-value semantics.) print hi there ; This has value () : unit and as a side effect prints to standard out. print ha! ; print( ha! ); prints ha!ha! This does work in ML if we abstract a function: let fun f () =(print ha! ) in f (); f () end; this prints ha!ha! and finally: However, if we try to abstract this: let val x =(print ha! ) in x ; x end; then the laugh is on us... let fun f () =(print ha! ) in 3+4 end; this evaluates to 7 (and doesn t guffaw) Or consider: let val x =(print ha! ) in 3+4 end; Alan Borning 7 CSE 505 Alan Borning 8 CSE 505

Monads and Equational Reasoning: Haskell Now consider the same examples in Haskell. puts ha! >> puts ( ha! ); is the command that, if it is ever executed, prints ha!ha! We can abstract this: let x =(puts ha! ) in x >> x to give the command that, if it is ever executed, prints ha!ha! Further: let x =(puts ha! ) in 3+4 Commands that Yield Values getchar :: IO Char if the input buffer contains ABC and we perform the getchar command then the command yields A, leaving BC in the buffer. The return command does nothing and returns a value. return :: a -> IO a (We need this so that we can return values from commands -- if we just tried to include the value in a sequence of commands the type would be wrong.) The done command isn t actually built in -- but we can define it as done :: IO () done = return () if evaluated, has value 7 (as expected) Alan Borning 9 CSE 505 Alan Borning 10 CSE 505 Primitives for Combining Commands that Yield Values (>>=) :: IO a -> (a -> IO b) -> IO b (Again, in Haskell 98 this actually has a more general type. Thus if m and n are commands, then m>>=n is the command that, if it is performed, first performs m, which should yield a value x. It then performs n, passing x as a parameter. The value returned by n is the value of the whole command m>>=n Example: getchar >>= putchar gets a character and then puts it. We can use this to define a command to get n characters from the input: gets 0 = return [] gets (i+1) = getchar >>= \c -> gets i >>= \s -> return (c:s) An Analog of Let Rather than m>>=n we can write do x <- m n x This is the command, that if it is ever performed, first performs m and binds the resulting value to x. It then performs n, passing x as a parameter. The value returned by n is the value of the whole command. Caution regarding layout rules: the version above works, but the following doesn t: do x <- m n x Thus: do c <- getchar putchar c main = (gets 10) >>= puts Alan Borning 11 CSE 505 Alan Borning 12 CSE 505

More Examples of Do Some built-in I/O commands in Haskell: gets 0 = return [] gets (i+1) = do c <- getchar s <- gets i return (c:s) -- get 10 characters and print them main = do str <- (gets 10) puts str Output Functions These functions write to the standard output device (this is normally the user s terminal). putchar :: Char -> IO () putstr :: String -> IO () putstrln :: String -> IO () -- adds a newline print :: Show a => a -> IO () The print function outputs a value of any printable type to the standard output device (this is normally the user s terminal). Printable types are those that are instances of class Show; print converts values to strings for output using the show operation and adds a newline. For example, a program to print the first 20 integers and their powers of 2: main = print ([(n, 2^n) n <- [0..19]]) Alan Borning 13 CSE 505 Alan Borning 14 CSE 505 Input Functions Read and Show These functions read input from the standard input device (normally the user s terminal). getchar :: IO Char getline :: IO String getcontents :: IO String interact :: (String -> String) -> IO () readio :: Read a => String -> IO a readline :: Read a => IO a Both getchar and getline raise an exception on end-of-file. The getcontents operation returns all user input as a single string, which is read lazily as it is needed. The interact function takes a function of type String->String as its argument. The entire input from the standard input device (normally the user s terminal) is passed to this function as its argument, and the resulting string is output on the standard output device. (From Section 7 of the Haskell Report). show :: (Show a) => a -> String example: show (3.2+4.1) => 7.3 read :: (Read a) => String -> a examples: read 3.2 + 10.0 => 13.2 read 3.2 :: Double => 13.2 (however, the type system will be unhappy with just read 3.2 since it won t be able to resolve the overloading) Alan Borning 15 CSE 505 Alan Borning 16 CSE 505

The Monadic Calculator -- Haskell calculator (demonstrates a simple -- interactive program using monads) -- see ~borning/haskell/calc.hs calc = do putstr first number: a <- readln putstr second number: b <- readln putstr sum: putstrln (show (a+b)) putstr again? again <- getline if head again == y then calc else return () Other Useful Functions for I/O lines -- break up a string into substrings at the newline chars lines :: String -> [String] unlines -- put it back together unlines :: [String] -> String lex -- gets the first token from a string, returning a tuple with the token and the remaining part of the string lex 3*x+2*y => ( 3, *x+2*y ) Alan Borning 17 CSE 505 Alan Borning 18 CSE 505 Showing Showing using Derived Instances Consider the Tree type: (see the file ~borning/haskell/tree1.hs) data Tree a = Leaf a Branch (Tree a) (Tree a) We can write a show function as follows: showtree :: (Show a) => Tree a -> String We can generate a show method automatically using derived instances. This version is on ~borning/haskell/tree2.hs data Tree a = Leaf a Branch (Tree a) (Tree a) deriving show showtree (Leaf x) = show x showtree (Branch l r) = < ++ showtree l ++ ++ showtree r ++ > sample = (Branch (Branch (Leaf 1) (Leaf 2)) (Leaf 3)) Then showtree sample => <<1 2> 3> sample = (Branch (Branch (Leaf 1) (Leaf 2)) (Leaf 3)) Then sample prints as Branch (Branch (Leaf 1) (Leaf 2)) (Leaf 3) We can definite this as an instance of Show to use the generic overloaded show functions (so that trees will print using showtree): instance Show a => Show (Tree a) where show t = showtree t Alan Borning 19 CSE 505 Alan Borning 20 CSE 505

ReadS and ShowS showtree ends up doing extra concatenation -- we can avoid this by passing along an accumulator (stored in ~borning/ haskell/tree3.hs) -- version of showtree that uses an accumulator showstree :: (Show a) => Tree a->string->string showstree (Leaf x) s = shows x s showstree (Branch l r) s = < : showstree l ( : showstree r ( > : s)) Object Level to Function Level from the Gentle Introduction: Something more important than just tidying up the code has come about by this transformation: We have raised the presentation from an object level (in this case, strings) to a function level. We can think of the typing as saying that showstree maps a tree into a showing function. Functions like ( < :) or ( a string ++) are primitive showing functions, and we build up more complex functions by function composition. Then showstree sample => <<1 2> 3> -- and a version using functional composition: showstree2 :: (Show a) => Tree a -> ShowS showstree2 (Leaf x) = shows x showstree2 (Branch l r) = ( < :). showstree l. ( :). showstree r. ( > :) showstree2 sample => <<1 2> 3> Alan Borning 21 CSE 505 Alan Borning 22 CSE 505