Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Функциональные языки: общие вопросы > Очень хитрая логическая ошибка


Автор: afiskon 20.6.2011, 11:20
Читаю http://www.haskell.org/haskellwiki/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.

Автор: calabiyau 21.6.2011, 14:56
Цитата(afiskon @  20.6.2011,  11:20 Найти цитируемый пост)
Что скажите, господа? Я не могу найти логическую ошибку. А вы?

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

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


или:
Код

copyFile src dst = bracket (openFile src ReadMode) hClose (hGetContents >=> writeFile dst)

Автор: afiskon 21.6.2011, 16:37
С ума сойти smile Спасибо!

Автор: ruberoid 15.9.2011, 13:42
Я бы тоже сам не разобрался. Так всё запутанно. smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)