fugafuga.write

日々のログ

すごいH本 part62

Todoリスト

Todoリストをテキストファイルに追加するプログラムを書く

import System.IO

main = do
    todoItem <- getLine
    appendFile "todo.txt" (todoItem ++ "\n")

ビルドして実行

> stack ghc -- --make appendtodo.hs
[1 of 1] Compiling Main             ( appendtodo.hs, appendtodo.o )
Linking appendtodo ...
> ./appendtodo
line one.
> cat todo.txt
line one.
> ./appendtodo
line two.
> cat todo.txt
line one.
line two.

アイテムの削除

Todoリストのアイテム削除するプログラムを書く

import System.IO
import System.Directory
import Data.List

main = do
    contents <- readFile "todo.txt"
    let 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
    let number = read numberString
        newTodoItems = unlines $ delete (todoTasks !! number) todoTasks
    (tempName, tempHandle) <- openTempFile "." "temp"
    hPutStr tempHandle newTodoItems
    hClose tempHandle
    removeFile "todo.txt"
    renameFile tempName "todo.txt"

ビルドして実行

> stack ghc -- --make deletetodo.hs
[1 of 1] Compiling Main             ( deletetodo.hs, deletetodo.o )
Linking deletetodo ...
> cat todo.txt
11111111111111
2222222222222
33333333333333
444444444444444
55555555555555
> ./deletetodo
These are your TO-DO items:
0 - 11111111111111
1 - 2222222222222
2 - 33333333333333
3 - 444444444444444
4 - 55555555555555
Which one do you want to delete?
2
> cat todo.txt
11111111111111
2222222222222
444444444444444
55555555555555
> ./deletetodo
These are your TO-DO items:
0 - 11111111111111
1 - 2222222222222
2 - 444444444444444
3 - 55555555555555
Which one do you want to delete?
3
> cat todo.txt
11111111111111
2222222222222
444444444444444

クリーンアップ

ファイルを開いた状態で異常終了するとtempファイルが残るので、 その対応をする。

Controll.Exception にある bracketOnError を使う

bracketOnError は何かしらの例外が発生したときのみリソースを解放する。

import System.IO
import System.Directory
import Data.List
import Control.Exception

main = do
    contents <- readFile "todo.txt"
    let 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
    let 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 "todo.txt"
            renameFile tempName "todo.txt")

1つ目の引数にエラー時の処理, 2つ目の引数に正常時の処理を書く。

実行

> stack ghc -- --make deletetodo.hs
[1 of 1] Compiling Main             ( deletetodo.hs, deletetodo.o )
Linking deletetodo ...
> ./deletetodo
These are your TO-DO items:
0 - 11111111111111
1 - 2222222222222
2 - 444444444444444
Which one do you want to delete?
2
> cat todo.txt
11111111111111
2222222222222

所感

異常系も少しずつ扱えるようになってきて、 アプリケーションらしいものが書けることの喜びを噛み締めている。

すごいHaskellたのしく学ぼう!

すごいHaskellたのしく学ぼう!

  • 作者: MiranLipovaca
  • 出版社/メーカー: オーム社
  • 発売日: 2017/07/14
  • メディア: Kindle版
  • 購入: 4人 クリック: 9回
  • この商品を含むブログを見る