Все еще довольно плохо знаком с Haskell ..
Я хочу прочитать содержимое файла, сделать что-то с ним, возможно, с использованием ввода-вывода (сейчас использую 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
s не являются строгими по своей природе?
Кто-нибудь может порекомендовать лучший, более короткий способ сделать это, сохранив желаемую семантику?
Спасибо!