Очень хитрая логическая ошибка

 
0
 
Functional languages
ava
afiskon | 20.06.2011, 12:20
Читаю 14 занимательных эссе о языке Haskell и функциональном программировании Романа Душкина. В одно из глав приводится следующий код:


copyFile:: String -> String -> IO()
copyFile src dst = do
  body <- readFile src
  writeFile dst body
  putStrLn ("Файл '" ++ src ++ "' скопирован в '" ++ dst ++ "'.")

main:: IO()
main = do
  putStrLn "Пожалуйста, введите имя файла для копирования: "
  src <- getLine
  putStrLn "Введите новое имя файла: "
  dst <- getLine
  catch ( copyFile src dst ) (\e -> do
    putStrLn "Ошибка. Пожалуйста, повторите."
    main)


И дается комментарий к нему:

Цитата


Рекурсивный вызов функции main не должен настораживать - это обычное дело. И опять же, имеется много возможностей для улучшения этой функции. Можно распознавать тип произошедшей ошибки и выводить на экран соответствующее сообщение. Можно не заставлять вводить пользователя оба имени снова, а просить вводить только то, с которым произошла ошибка. Можно придумать много чего еще. Все эти новые возможности опять оставляются для самостоятельной проработки.



Кроме того, вдумчивый читатель увидит здесь одну логическую ошибку, которая нарочито оставлена в целях обучения. Эта ошибка не приводит к генерации исключения, но может быть причиной непредсказуемого поведения программы. Кто первый из читателей сообщит о ней и о возможном способ ее преодоления автору, получит интересный подарок.



Что я только не пробовал - и /dev/zero в /dev/null копировал (казалось бы, должна кончится память - ан нет, ленивые вычисления) и /dev/random на раздел ограниченного размера, и пустой файл копировал, куда только можно. Разве что сигналы не посылал, но с ними поведение программы как раз вполне предсказуемо. Даже если мы попытаемся писать в unix-socket и внезапно закроем его - программа просто умрет из-за SIGPIPE. Ничего непредсказуемого.

Что скажите, господа? Я не могу найти логическую ошибку. А вы?

UPD: Да, фоновый процесс тоже успешно ждет, когда его реанимируют с помощью fg.
Comments (3)
ava
calabiyau | 21.06.2011, 14:56 #
Цитата (afiskon @  20.6.2011,  11:20 findReferencedText)
Что скажите, господа? Я не могу найти логическую ошибку. А вы?

хэндл открытого на чтение файла будет висеть если writeFile dst body кинет исключение (пока не отработает сборщик мусора). А значит, если на энной итерации мы обратимся к нему на запись, успешность операции будет зависеть от того, прошелся ли гц, али нет.

catch ( copyFile src dst ) (\e -> do
    putStrLn "Ошибка. Пожалуйста, повторите."
    performGC
    main)


или:

copyFile src dst = bracket (openFile src ReadMode) hClose (hGetContents >=> writeFile dst)
ava
afiskon | 21.06.2011, 16:37 #
С ума сойти smile Спасибо!
ava
ruberoid | 15.09.2011, 13:42 #
Я бы тоже сам не разобрался. Так всё запутанно. smile 
Please register or login to write.
Firm of day
Вы также можете добавить свою фирму в каталог IT-фирм, и публиковать статьи, новости, вакансии и другую информацию от имени фирмы.
Подробнее
Contributors
advanced
Submit