Уборка

Чтобы гарантировать удаление временного файла, воспользуемся функцией bracketOnError из модуля Control.Exception. Она очень похожа на bracket, но если последняя получает ресурс и гарантирует, что освобождение ресурса будет выполнено всегда, то функция 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 ( line –> show n ++ " – " ++ line)

                               [0..] todoTasks

   putStrLn "Ваши задания:"

   mapM_ putStrLn numberedTasks

   putStrLn "Что вы хотите удалить?"

   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")

Вместо обычного использования функции openTempFile мы заключаем её в bracketOnError. Затем пишем, что должно произойти при возникновении исключения: мы хотим закрыть и удалить временный файл. Если же всё нормально, пишем новый список заданий во временный файл; все эти строки остались без изменения. Мы выводим новые задания, удаляем исходный файл и переименовываем временный.