Ответ 1
Как отметил Габриэль, проблема заключается в том, что readFile
считывает содержимое файла по требованию и закрывает основной дескриптор файла только тогда, когда содержимое файла полностью потребляется.
Решение состоит в том, чтобы потребовать полное содержимое файла, чтобы обработчик закрылся перед тем, как сделать writeFile
.
Короткий ответ: используйте readFile из строгой версии.
import qualified System.IO.Strict as SIO
import Data.Functor
myAppendFile :: FilePath -> IO String
myAppendFile file = do
x <- SIO.readFile file
writeFile file "1"
appendFile file x
return x
main :: IO ()
main = void $ myAppendFile "data"
Другим простым "взломом" для этого является использование seq
:
myAppendFile :: FilePath -> IO String
myAppendFile file = do
x <- readFile file
length x `seq` writeFile file "1"
appendFile file x
return x
seq a b
в основном просто b
плюс, что когда b
требуется, a
(length x
в этом случае) оценивается как WHNF перед тем, как проверять b
, это потому, что length
требует, чтобы его аргумент (x
в этом случае) проходил до тех пор, пока не будет показан пустой список []
, поэтому требуется полное содержимое файла.
Имейте в виду, что с помощью строгого ввода-вывода ваша программа будет хранить все содержимое файла (в виде списка Char
s) в памяти. Для игрушечных программ это прекрасно,
но если вы заботитесь о производительности, вы можете взглянуть на bytestring или text в зависимости от независимо от того, связана ли ваша программа с байтами или текстами (если вы хотите иметь дело с текстом unicode). Они намного эффективнее, чем String
.