简体   繁体   中英

Haskell: preventing data modification

I have the following code which does the job of changing the configuration file:

mutateConfig :: (Config -> Config) -> IO ()
mutateConfig f = do
    !cfg <- readConfig
    let !newCfg = f cfg
     in writeConfig newCfg

Bang patterns are used to disable lazy evaluation: i need writeConfig to be called after an old configuration was parsed and modified with function f .

But there is still a problem: imagine that f gives an error. In this case writeConfig has already opened the file for writing (because it is called first by lazy evaluation) when an error occures, so the configuration file gets lost.

I have tried to compose a simple step-by-step logic from IO monads (in order to prevent the loss of data) like this

!cfg <- readConfig
newCfg <- return $ f cfg
writeConfig newCfg

but this doesn't work either (I kind of expected that).

What would be the correct way to accomplish this goal?

If Config is completely strict (no embedded bottoms within), you can do this:

do
    cfg <- readConfig
    let newCfg = f cfg
    evaluate newCfg
    writeConfig newCfg

If it's not, you could do something like evaluate ( deepseq newCfg ()) .

But there's another problem: In general, writing a file can fail due to I/O errors (for example because the disk is full). To avoid this, you can write to a temporary file and rename it to the real target at the end. Doing it this way guarantees you only overwrite the config if there were no errors during the writing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM