Еще новичок в Haskell..
Я хочу прочитать содержимое файла, сделать что-то с ним, возможно, с использованием IO (используя putStrLn), а затем записать новое содержимое в тот же файл.
Я придумал:
doit :: String -> IO ()
doit file = do
contents <- withFile tagfile ReadMode $ \h -> hGetContents h
putStrLn contents
withFile tagfile WriteMode $ \h -> hPutStrLn h "new content"
Однако это не работает из-за лени. Содержимое файла не печатается. Я нашел этот пост, который объясняет это хорошо.
Предлагаемое решение должно включать putStrLn
в пределах withFile
:
doit :: String -> IO ()
doit file = do
withFile tagfile ReadMode $ \h -> do
contents <- hGetContents h
putStrLn contents
withFile tagfile WriteMode $ \h -> hPutStrLn h "new content"
Это работает, но это не то, что я хочу делать. Операция в я в конечном итоге заменит putStrLn
может быть длинной, я не хочу держать файл открытым все время. В общем, я просто хочу получить содержимое файла, а затем закрыть его перед тем, как работать с этим контентом.
Решение, которое я придумал, следующее:
doit :: String -> IO ()
doit file = do
c <- newIORef ""
withFile tagfile ReadMode $ \h -> do
a <- hGetContents h
writeIORef c $! a
d <- readIORef c
putStrLn d
withFile tagfile WriteMode $ \h -> hPutStrLn h "Test"
Однако, я нахожу это длинным и немного запутанным. Я не думаю, что мне понадобится IORef
, чтобы получить ценность, но мне нужно "место", чтобы поместить содержимое файла. Кроме того, он все еще не работал без аннотации строгости $!
для writeIORef
. Я думаю, IORef
не являются строгими по своей природе?
Может ли кто-нибудь рекомендовать лучший, более короткий способ сделать это, сохраняя мою желаемую семантику?
Спасибо!