How do I write writeFile with any data type?

I have a function that takes some arguments and returns IO (Either String String)

, say

testEither :: Int -> IO (Either String String)
testEither 0 = return (Left "we got an error")
testEither _ = return (Right "everything is ok")

      

(The real function extracts some things from the real world and may fail)

I want to send the output of this function to writeFile fileName

. Expected Behavior: If I bind testEither 0

to writeFile "test.txt"

, I fail with Left ...

, and if I call it with testEither 1

, I get everything is ok

in a file test.txt

.

I am guessing that the type of the entire expression should be something like IO (Either String ())

, but I could be wrong.

+3


source to share


4 answers


You can use ErrorT 1 monad transformer to give you clean error handling on top of the IO

monad:

import Control.Monad.Error

testEither :: Int -> IO (Either String String)
testEither 0 = return (Left "we got an error")
testEither _ = return (Right "everything is ok")

main = runErrorT $ do
    result <- ErrorT $ testEither 0
    lift $ writeFile "test.txt" result

      



1ErrorT

appears to have been replaced with ExceptT

in the newest version mtl

, but the functionality should be similar.

+3


source


It's easy to use with an Either

Traversable

instance:



import Data.Traversable

main = do
    traverse (writeFile "test.txt") (Left "we got an error")
    traverse (writeFile "test.txt") (Right "everything is ok")

      

+3


source


This won't happen automatically, but you can easily use pattern matching to accomplish this:

writeFileEither :: FilePath -> Either a String -> IO ()
writeFileEither _  (Left _) = return ()
writeFileEither fp (Right text) = writeFile fp text

      

Then you can link them together with

main = testEither 1 >>= writeFileEither "test.txt"

      

Or with the designation:

main = do
    result <- testEither 1
    writeFileEither "test.txt" result

      

+1


source


Below is a function main

that shows how to use testEither

in IO

: if it testEither

returns an error then the error is written to stderr

otherwise the correct result is fetched from Right

and written to a file test.txt

:

import System.IO

testEither :: Int → IO (Either String String)
testEither 0 = return (Left "we got an error")
testEither _ = return (Right "everything is ok")

main :: IO 𐌏
main = do
  res ← testEither 0
  case res of
    Left err → hPutStrLn stderr ("Error: " ++ err)
    Right s  → writeFile "test.txt" s

      

0


source







All Articles