程序代写 Microsoft PowerPoint – Week6.pptx

Microsoft PowerPoint – Week6.pptx

2022‐10‐12

Copyright By PowCoder代写 加微信 powcoder

Ch 9: More Input and More Output
Ch 10: Functionally Solving Problems

University of the Fraser Valley

COMP 481: Functional and Logic Programming

• Reading and Writing Files

• The Bracket Function

• Writing with Handles

• To‐Do Function

• Command‐Line Arguments

• Handling Bad Input

• Randomness

• Toss a Coin

• Sequences of Random Numbers

• Randomness and I/O

• ByteStrings

• Strict and Lazy ByteStrings

• Copying Files with ByteStrings

Chapter 10
• Reverse Polish Notation Calculator

• Writing an RPN Function

• Adding More Operations

• Heathrow to London

• Using Input for the Road System

2022‐10‐12

Operations 

import Data.List

‐‐ Get a list of unique sums from the sums of all possible pairs 
of items from list1 and list2

list1 = [5, 6, 7, 8]

list2 = [1, 2, 3, 4]

method1 = nub [a+b | a <‐ list1, b <‐ list2] method2 = nub $ fmap (+) list1 <*> list2

method3 = nub $ (+) <$> list1 <*> list2

method4 = nub $ pure (+) <*> list1 <*> list2

method5 = nub $ [(+)] <*> list1 <*> list2

Streams are sequences of data supplied over time.

• similar to characters supplied by keyboard as the user types them

• not much random access, only the next character in the sequence

2022‐10‐12

File Input

Save the following text data as `haiku.txt` in a subfolder 
named `data`:

I’m a lil’ teapot

What’s with that airplane food, huh?

It’s so small, tasteless

Then save the following script as `capslocker.hs`:

{‐ ### capslocker.hs v1 ### ‐}

import Control.Monad

import Data.Char

main = forever $ do

l <‐ getLine putStrLn $ map toUpper l Command‐Line  Compile and  Compile the program and execute with a redirect: stack ghc capslocker.hs capslocker < data\haiku.txt (Windows) ./capslocker < data/haiku.txt (Unix‐like) Choose the above execute based on your platform. • in Windows, there is no need for the `./` prefix • the redirect `<` takes the contents of the `haiku.txt` file one line at a  time and pipes it into standard input • this is the same as if we had typed it on the keyboard while  `capslocker` executed 2022‐10‐12 getContents We can simplify the `capslocker` program by making use of  `getContents` function. • `getContents` does lazy I/O in Haskell • it gets the input when required later, instead of right away • it reads standard input until it gets an end‐of‐file character • its type is `getContents :: IO String` • it takes care of how much input to get for us, unlike `forever` {‐ ### capslocker.hs v2 ### ‐} import Data.Char contents <‐ getContents putStr $ map toUpper contents getContents To run `capslocker` without redirected input, user input will  continue to get echoed as capitalized messages to stdout: • to stop the program, send it an end‐of‐file signal • in Windows, press `CTRL‐Z` and then press `ENTER` • in other platforms, press `CTRL‐D` Some notes about execution involving `getContents`: • `getContents` makes a promise to keep processing more lines of  input, one line at a time • it does not process a line in the future until it is typed • because `contents` is bound to `getContents`, it acts similarly • because `map toUpper` takes `contents` as input, it also promises  to execute per line as entered • they all repeat execution for each line until an end‐of‐file character is  2022‐10‐12 We can practice lazy input like this more with a program  that restricts which input should be displayed depending  on length: {‐ ### shortLinesOnly.hs v1 ### ‐} contents <‐ getContents putStr (shortLinesOnly contents) shortLinesOnly :: String ‐> String

shortLinesOnly =

unlines . filter (\line ‐> length line < 10) . lines • `lines` and `unlines` functions behave like `words` and `unwords` • but for input separated by end‐of‐line characters split into elements  of a list and back shortLinesOnly Save the following text in the `data` folder as `short.txt`: {‐ ### data\short.txt ### ‐} i am a loooooooooong line!!! yeah i'm long so what hahahaha!!!!!! short line loooooooooooooooooooooooooooong * go ahead and redirect the above text file into `shortLinesOnly` 2022‐10‐12 *shortLinesOnly The previous implementation has a useful function to do  the same kind of operations on each line of input: {‐ ### shortLinesOnly.hs v2 ### ‐} main = interact shortLinesOnly shortLinesOnly :: String ‐> String

shortLinesOnly = 
unlines . filter (\line ‐> length line < 10) . lines • `interact` takes a function of type `String ‐> String` as a parameter 
and gives back an I/O action

• the I/O action performs the same execution as the previous version of 
our `shortLinesOnly` program

• i.e.: it processes one line at a time of streamed input

• * we can either redirect, or type lines of input ourselves

*Palindromes

We can practice `interact` more by writing `palindromes.hs` 
to test whether a line of input is a palindrome.

• a palindrome is a string with characters in forward sequence that 
also have the same sequence backward

• let us write a function to pass to `interact` so that it replaces 
palindromes with

• “palindrome”, or

• “not palindrome”

2022‐10‐12

*Palindromes

{‐ ### palindromes.hs ### ‐}

main = interact respondPalindromes

respondPalindromes :: String ‐> String

respondPalindromes = 

. map (\line ‐> 

if isPal line 

then “palindrome” 

else “not palindrome“

isPal :: String ‐> Bool

isPal xs = xs == (reverse xs)

*Palindromes

Try out palindromes.hswith some input:

{‐ ### data\words.txt ### ‐}

2022‐10‐12

— Reading and Writing Files —

hGetContents

Save the following in a file called `data/girlfriend.txt` (from 
‘s hit song “Girlfriend”):

Hey! Hey! You! You!

I don’t like your girlfriend!

No way! No way!

I think you need a new one!

First, read file contents and print it to standard output:

{‐ ### girlfriend.hs v1 ### ‐}

import System.IO

handle <‐ openFile "data/girlFriend.txt" ReadMode contents <‐ hGetContents handle putStr contents hClose handle 2022‐10‐12 • `openFile :: FilePath ‐> IOMode ‐> IO Handle`

• parameters take:
• (1) a specified file, 

• (2) an IOMode (`ReadMode`), and 

• (3) an I/O action to open a file and yield the file’s associated handle

• `FilePath` is just a type synonym for `String`, 
i.e.: `type FilePath = String`

• `IOMode` is defined like so:

• `data IOMode =
ReadMode | WriteMode | AppendMode | ReadWriteMode`

• (note that it is not `IO Mode` with a space, which would be an I/O 
action with yield of `Mode`)

• `IOMode` is just an enumeration

• programs in general (not just Haskell) are allowed by the OS to work 
with a file by its file descriptor

• the file descriptor in Haskell is typed as a `Handle` that implements a 
bit more functionality with the mode

• `getContents` works with standard input
• `hGetContents` works with specified files
• these functions are altogether otherwise the same

• `hGetContents` will only load parts of the file as needed, which helps 
when we are loading a large file to avoid hogging RAM

• `handle` points to current location in the file to keep track of reading it

• `putStr` is familiar

• `hClose` takes a handle and returns an I/O action that closes the file

• always close a resource obtained from outside of your program
• otherwise, the program could terminate trying to open a file with a 
handle that has not been closed

2022‐10‐12

Function `withFile` compacts the execution of our previous 
program, and it has the following signature:

withFile :: FilePath ‐> IOMode ‐> (Handle ‐> IO a) ‐> IO a

• `FilePath` takes a specified file

• `(Handle ‐> IO a)` function 

• lastly, `withFile` returns an I/O action
• it will open the file
• perform some action with the function passed in
• close the file
• if anything goes wrong, `withFile` makes sure to close the file

{‐ ### girlfriend.hs v2 ### ‐}

import System.IO

withFile “data/girlfriend.txt” ReadMode

(\handle ‐> do

contents <‐ hGetContents handle putStr contents • `(\handle ‐> do …)` function ( :: handle ‐> I/O a )

• it is typical to pass it in as a lambda this way

• `withFile` makes sure to close the file handle if anything goes wrong

2022‐10‐12

Exceptions

Errors during execution that happen (e.g.: calling `head` on 
an empty list) typically print an error message:

• these are called exceptions

• `withFile` ensured a file handle is closed when an exception is raised

• for any resource (such as a file), we need to ensure it is released 
given any situation or error

Then the common design for working with a resource and 
dealing with input and output using it is as follows:

• get the resource as an I/O action

• ensure it can be closed regardless of exception

• process the data of the resource as an I/O action

• (altogether, these describe an I/O action of the resource type)

— The Bracket Function —

2022‐10‐12

Then the following type for the `bracket` function…

bracket :: IO a ‐> (a ‐> IO b) ‐> (a ‐> IO c) ‐> IO a

…matches its parameters (and return type) for the 
common design described.

• the first `IO a` is the resource obtained, but as an I/O action

• `(a ‐> IO b)` is a function to execute regardless of exception

• `(a ‐> IO c)` is a function to process the resource

• the last `IO a` needs to match context of input I/O action `IO a`

Then implementing a function such as `withFile` becomes 
very concise:

{‐ example of exception handling ‐}

withFile’ :: FilePath ‐> IOMode ‐> (Handle ‐> IO a) ‐> IO a

withFile’ name mode f =

bracket (openFile name mode)

(\handle ‐> hClose handle)

(\handle ‐> f handle)

2022‐10‐12

—Working with Handles —

There are counterpart functions for the same actions with 
handles that we have been doing with stdin and stdout:

• `hGetLine`

• `hPutStr`

• `hPutStrLn`

• `hGetChar`

2022‐10‐12

Using files as if they were large strings is very common, so 
we have three more functions to help with this:

• `readFile :: FilePath ‐> IO String` take a specified file and 
performs I/O read action (lazily) and can bind to some variable

• a bit more concise than calling `openFile` and then `hGetContents`

• `writeFile :: FilePath ‐> String ‐> IO ()` takes a specified file, a 
string, and performs I/O write action

• if the file already exists, its contents are first erased before writing

• `appendFile :: FilePath ‐> String ‐> IO ()`

• same as `writeFile`, but does not erase contents first, and instead 
appends the given string after the contents of the file

(Simranjit Singh)

import System.IO

import Data.Char

main :: IO ()

line <‐ getLine let num = read line :: Int contents <‐ readFile "msg.txt" writeFile "secretmsg.txt" (encode num contents) encode :: Int ‐> String ‐> String

encode offset msg = map (\c ‐> chr $ ord c + offset) msg

2022‐10‐12

appendFile

import System.IO

student <‐ getLine appendFile "classList.txt" (student ++ ", ") File classList.txt: Directories  import System.IO import System.Directory import Data.List import System.Process createDirectoryIfMissing False "planner" contents <‐ getDirectoryContents "planner" let cats = unlines contents putStrLn "Choose Subject:" putStrLn cats catName <‐ getLine putStrLn "Enter assignment name:" newAssign <‐ getLine appendFile ("planner/" ++ catName ++ ".txt") (newAssign ++ "\n") 2022‐10‐12 Directories  • getDirectoryContents will show `.` and `..` • listDirectory is the same, but does not show `.` and `..` • (we have seen appendFile in a previous example) — To‐Do List — 2022‐10‐12 To‐Do List We have enough to write an application to keep a list of  things we would like to do and store them in a file for us. Creating files involves POSIX libraries, so for now, create  the `data/todo.txt` file, and write the following program:  {‐ ### todo.hs v1 ### ‐} import System.IO todoItem <‐ getLine appendFile "data/todo.txt" (todoItem ++ "\n") To‐Do List Type in some chores, but as it is, you have to run the  program for each to do item you want to add: {‐ ### data\todo.txt ### ‐} iron the dishes dust the dog take the salad out of the oven • you can observe the contents of the to do list file with  • `cat data/todo.txt` in Bash,  • and with `type data/todo.txt` in Windows CMD 2022‐10‐12 {‐ ### deletetodo.hs v1 ### ‐} import System.IO import System.Directory import Data.List conetents <‐ readFile "data/todo.txt" todoTasks = lines contents numberedTasks =  zipWith (\n line ‐> show n ++ ” ‐ ” ++ line)

[0..] todoTasks

putStrLn “These are your TO‐DO items:”

mapM_ putStrLn numberedTasks

putStrLn “Which one do you want to delete?”

numberString <‐ getLine (cont’d on next slide…) number = read numberString newTodoItems =  unlines $ delete (todoTasks !! number) todoTasks (tempName, tempHandle) <‐ openTempFile "." "temp" hPutStr tempHandle newTodoItems hClose tempHandle removeFile "data/todo.txt" renameFile tempName "data/todo.txt“ 2022‐10‐12 • `todoTasks` stores a list of lines from the `todo.txt` file • it looks something like `["iron…","dust…","take the salad…"]` • `zipWith` prefixes a number to each line in the `todoTasks` list • `numberedTasks` looks something like `["0 – iron…","1 – dust…","2 ‐ take the salad…"]` • `mapM_` prints out the `numberedTasks`, each element on a separate  • `number` gets assigned to a choice from the user of which numbered  line to delete • `!!` accesses the element we want, and `delete` removes the first  occurrence of it from the list • `unlines` combines the edited list back into one string (with end‐of‐ line characters between elements) • the function `openTempFile` is a round‐about way to later replace the  old todo list file • `openTempFile`  takes two parameters: • a temporary directory, which we give as the current directory "." • the prefix to a temporary file name, which we call "temp", and a few  random digits are added • the new temporary file name and handle are returned in a pair • we use the temporary file to write the new edited list and replace  the old file 2022‐10‐12 Exceptions There are some issues with the `deletetodo.hs`: • if the program terminates from some kind of error • the temporary file is created,  • but not renamed • we need functionality similar to `bracket` where • a resource gets cleaned up automatically when we are done • but only if there is some kind of exception {‐ ### deletetodo.hs v2 ### ‐} import System.IO import System.Directory import Data.List import Control.Exception contents <‐ readFile "data/todo.txt" todoTasks = lines contents numberedTasks =  zipWith (\n line ‐> show n ++ ” ‐ ” ++ line)

[0..] todoTasks

putStrLn “These are your TO‐DO items:”

mapM_ putStrLn numberedTasks

putStrLn “Which one do you want to delete?”

numberString <‐ getLine `bracketOnError`  `Control.Exception`  2022‐10‐12 number = read numberString newTodoItems = unlines $ delete (todoTasks !! number) todoTasks bracketOnError (openTempFile "." "temp") (\(tempName, tempHandle) ‐> do

hClose tempHandle

removeFile tempName

(\(tempName, tempHandle) ‐> do

hPutStr tempHandle newTodoItems

hClose tempHandle

removeFile “data/todo.txt”

renameFile tempName “data/todo.txt”

The parameters of 
`bracketOnError`: 

• the resource first
• what to do on an exception
• what to do as expected normally

— Command‐Line Arguments —

2022‐10‐12

Command‐Line 

The To‐Do App limitations only work with the one text file, 
and only add or delete one item from a list one at a time.

Instead, we can specify what we would like our program to 
do exactly when we execute it. We use `System.Environment`:

• it lets us read command‐line arguments:

{‐ ### argTest.hs ### ‐}

import System.Environment

import Data.List

args <‐ getArgs progName <‐ getProgName putStrLn "The arguments are:" mapM putStrLn args putStrLn "The program name is:" putStrLn progName We combine the smaller example programs to insert and  delete items for our to‐do list. Altogether, we want the user to choose command‐line  options for controlling its functionality: • view tasks • add tasks • delete tasks To add a task to the `todo.txt` file, we will want to enter  into the terminal, and similarly for the other two options: (this is the desired behaviour from terminal execution) ./todo add todo.txt "Find the magic sword of power" ./todo view todo.txt ./todo remove todo.txt 2 2022‐10‐12 The program start will decide between which function to  run which matches the first command argument input: {‐ ### todo.hs part 1 ### ‐} import System.Environment import System.Directory import System.IO import Data.List dispatch :: String ‐> [String] ‐> IO ()

dispatch “add” = add

dispatch “view” = view

dispatch “remove” = remove

(command:argList) <‐ getArgs dispatch command argList • in `main` we first get the arguments matched with pattern  `(command:argList)` • then `command` should pattern match with one of the defined  versions of the `dispatch` function • the result returns the function to apply to the `argList` So, suppose we type in the terminal: ./todo add todo.txt "Find the magic sword of power" Then `main` should parse `add` as the command and  `["todo.txt", "Find the magic sword of power"]` 2022‐10‐12 Next, we implement the three functions for our app,  starting with `add`: {‐ ### todo.hs part 2, add v1 ### ‐} add :: [String] ‐> IO ()

add (filename:toDoItems) =

appendFile filename (unwords (toDoItems ++ [“\n”]))

• (no errors dealt with for mismatched file names until later)

• the rest of the list is dealt with as one long task to be 
appended on a new line at the end of the user‐specified file

• `unwords` will concatenate all string elements in the list together as one 
string separated by  a space

Before we move on to combine with the `view` and 
`remove` functions, add the following imports:

{‐ ### todo.hs part 3 ### ‐}

import Data.Foldable

import Control.Exception

2022‐10‐12

Foldable module is for `mapM_` and Exception module is for 
use of `bracketOnError` to handle potential file issues.

{‐ ### todo.hs part 4 ### ‐}

view :: [String] ‐> IO ()

view (filename:remainder) = do

contents <‐ readFile filename todoTasks = lines contents numberedTasks =  zipWith (\n line ‐> show n ++ ” ‐ ” ++ line)

[0..] todoTasks

putStrLn “These are your To‐Do items:”

mapM_ putStrLn numberedTasks

from To‐Do 

And basically the same function as before with `remove`:

{‐ ### todo.hs part 4 ### ‐}

remove :: [String] ‐> IO ()

remove [filename, numString] = do

contents <‐ readFile filename todoTasks = lines contents numberedTasks =  zipWith (\n line ‐> show n ++ ” ‐ ” ++ line)

[0..] todoTasks

putStrLn “These are your To‐Do items:”

程序代写 CS代考 加微信: powcoder QQ: 1823890830 Email: powcoder@163.com