软糖

Haskell 8 Input and Output

Taking Notes from http://learnyouahaskell.com

IO

  • 你能把 I/O action 想成是一个长了脚的盒子,它会跑到真实世界中替你做某些事
  • 打开盒子的唯一办法就是用 <-
  • 一个 I/O action 会在我们把它绑定到 main 这个名字并且运行程序的时候触发
  • do 表示法将所有 I/O action 绑成一个

Hello World

hello world 来的晚了点 :)

1
main = putStrLn "hello, world"
1
2
3
4
ghci> :t putStrLn
putStrLn :: String -> IO ()
ghci> :t putStrLn "hello, world"
putStrLn "hello, world" :: IO ()
  • return an I/O action
  • it container () () means return nothing
1
2
ghci> :t getLine
getLine :: IO String

Let Binding

1
2
3
4
5
6
7
8
9
10
import Data.Char
main = do
putStrLn "What's your first name?"
firstName <- getLine
putStrLn "What's your last name?"
lastName <- getLine
let bigFirstName = map toUpper firstName
bigLastName = map toUpper lastName
putStrLn $ "hey " ++ bigFirstName ++ " " ++ bigLastName ++ ", how are you?"
  • let bindings in expression (in expression is not required)

Example

1
2
3
4
5
6
7
8
9
10
main = do
line <- getLine
if null line
then return ()
else do
putStrLn $ reverseWords line
main
reverseWords :: String -> String
reverseWords = unwords . map reverse . words
  • return () means it return an IO ()
  • return will not stop program
1
2
3
4
main = do
a <- return "hell"
b <- return "yeah!"
putStrLn $ a ++ " " ++ b

Some IO methods

  • putStr :: String -> IO ()
  • putChar
  • putStrLn
  • print
    • 接受任何是 Show typeclass 的 instance 的型态的值
    • putStrLn 会打印出”, print不会
  • getChar :: IO Char

When

  • import Control.Monad will import when
1
2
3
4
5
6
7
import Control.Monad
main = do
c <- getChar
when (c /= ' ') $ do
putChar c
main

sequence

sequence :: [IO a] -> IO [a]

1
2
3
4
5
6
7
8
9
main = do
a <- getLine
b <- getLine
c <- getLine
print [a,b,c]
main = do
rs <- sequence [getLine, getLine, getLine]
print rs

mapM mapM_ forM

由于对一个串列 map 一个回传 I/O action 的函数,然后再 sequence 他这个动作太常用了

  • mapM 接受一个函数跟一个串列,将对串列用函数 map 然后 sequence 结果
  • mapM_ 也作同样的事,只是他把运算的结果丢掉而已
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ghci> mapM print [1,2,3]
1
2
3
[(),(),()]
ghci> mapM_ print [1,2,3]
1
2
3
import Control.Monad
main = do
colors <- forM [1,2,3,4] (\a -> do
putStrLn $ "Which color do you associate with the number " ++ show a ++ "?"
color <- getLine
return color)
putStrLn "The colors that you associate with 1, 2, 3 and 4 are: "
mapM putStrLn colors

forever

  • forever 接受一个 I/O action 并回传一个永远作同一件事的 I/O action
  • import Control.Monad
1
2
3
4
5
6
7
import Control.Monad
import Data.Char
main = forever $ do
putStr "Give me some input: "
l <- getLine
putStrLn $ map toUpper l

Stream

  • getChar
  • getLine
  • getContents :: IO String
1
2
3
4
5
6
7
import Data.Char
main = do
contents <- getContents
putStr (map toUpper contents)
$ cat haiku.txt | ./capslocker

File

1
2
3
4
5
man = do
handle <- openFile "test.txt" ReadMode
contents <- hGetContents handle
putStr contents
hClose handle
  • openFile :: FilePath -> IOMode -> IO Handle
  • type FilePath = String
  • data IOMode = ReadMode | WriteMode | AppendMode | ReadWriteMode
1
2
3
4
5
6
import System.IO
main = do
withFile "girlfriend.txt" ReadMode (\handle -> do
contents <- hGetContents handle
putStr contents)
  • withFile :: FilePath -> IOMode -> (Handle -> IO a) -> IO a
1
2
3
4
5
6
import System.IO
import Data.Char
main = do
contents <- readFile "girlfriend.txt"
writeFile "girlfriendcaps.txt" (map toUpper contents)
1
2
3
4
5
6
import System.IO
import Data.Char
main = do
contents <- readFile "girlfriend.txt"
writeFile "girlfriendcaps.txt" (map toUpper contents)
  • writefile :: FilePath -> String -> IO ()
1
2
3
4
5
import System.IO
main = do
todoItem <- getLine
appendFile "todo.txt" (todoItem ++ "\n")

Other functions:

  • hGetLine
  • hPutStr
  • hPutStrLn
  • hGetChar

Random

1
2
3
4
5
ghci> randomR (1,6) (mkStrGen 359353)
(6,1494289578 40692)
ghci> take 10 $ randomRs ('a','z') (mkStdGen 3) :: [Char]
"ndkxbvmomg"

System IO action

1
2
3
4
5
6
7
import System.Random
main = do
gen <- getStdGen
putStr $ take 20 (randomRs ('a','z') gen)
gen' <- newStdGen
putStr $ take 20 (randomRs ('a','z') gen')