- PVSM.RU - https://www.pvsm.ru -
Меня давно беспокоит одна тема. Вот решил высказаться и услышать, что думают люди по этому поводу. Речь пойдет о функции hGetContents. Если вы когда-нибудь работали с файлами, то вы знаете, что эта функция возвращает содержимое файла (потока). Вот типичный пример использования этой функции.
import System.IO
main = do
file <- openFile "1.txt" ReadMode
content <- hGetContents file
print content
hClose file
-- результат: выводит содержимое файла на экран
Все очень банально — открываем файл, считываем содержимое, выводим на экран, закрываем файл. Фича фунции hGetContents (а точнее фича Haskell-я) в том, что она ленивая. А именно, данные из файла считаются не сразу целиком, а будут считываться по мере необходимости. Например, вот такая программа
import System.IO
main = do
file <- openFile "1.txt" ReadMode
content <- hGetContents file
print $ take 3 content
hClose file
-- результат: выводит первые 3 символа из файла на экран
считает из файла только первые 3 символа.
Что тут можно сказать, отличная фича! Это очень удобно, оперировать переменной content (содержимое файла), но при этом знать, что Haskell возмет из него только то, что нужно, и ничего лишнего.
А теперь рассмотрим следующий пример
import System.IO
main = do
file <- openFile "1.txt" ReadMode
content <- hGetContents file
hClose file
print content
-- результат: выводит пустую строку
Здесь мы просто переставил местами две последние строчки. Результатом будет выведенная на экран пустая строка. Почему так получилось? Причина в том, что мы пытаемся обратиться к содержимому файла после того, как файл уже закрыт. При вызове hGetContents данные никуда не считывались, просто в переменной content сохранилась некоторая ссылка на этот файл. А потом, когда нам понадобилось содержимое content, оказалось, что файл уже закрыт.
Ну и что такого, подумаете Вы, просто нужно использовать переменную content до закрытия файла.
Я долго думал над этим примером и чувство «что-то здесь не так» не оставляло меня в покое. Разве это не нарушает чистоту Haskell-я. Я же написал корректную по сути программу, а она выдает не правильный результат. Я что должен думать о том, в какой момент он обратится к этой переменной и что он там вообще делает под капотом? Это уже не Haskell, это, извините за выражение, C++ какой-то.
В итоге я пришел к выводу, что эта «фича» — не фича, а баг. Если я вас не убедил, то вот несколько доводов:
Проблема тут еще в том, что мы никак не можем «заставить» Haskell вычислить переменную content до закрытия файла (если кто-то знает способ, напишите).
К чему я все это? Вы только не поймите меня не правильно. Я очень люблю Haskell. За его чистоту, ленивость, функциональность и еще много чего, что не выразить словами. Просто я вдруг узнал, что он не такой «чистый», как я раньше думал. Осталось какое-то смешанное чувство, что вроде бы и фича-то хорошая, но как-то «грязьненько» от неё стало.
Возможно у меня просто паранойя. Хотелось бы услышать ваше мнение, баг или фича?
Автор: Tazman
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/haskell/16584
Нажмите здесь для печати.