Guillaume
Guillaume

Reputation: 191

Haskell I can not get exception ReadFile with try

I have a function "management" that checks parameters and return a Maybe (String):

My problem arrived when I get a file and check if this file exists.

Couldn't match expected type ‘Maybe String’ with actual type ‘IO (Either e0 a2)’

managagment :: [String] -> Maybe (String)
managagment [] = Nothing
managagment ["-h"] = Just (help)
managagment [file] = try $ readFile file >>= \result -> case result of
                                                        Left e -> Nothing
                                                        Right content -> Just (content)

Upvotes: 0

Views: 810

Answers (1)

Thomas M. DuBuisson
Thomas M. DuBuisson

Reputation: 64740

There are several problems

Function application ($) is lower precedence than bind (>>=)

You said:

try $ readFile file >>= \res...

Which means

try ( readFile file >>= \res... )

But you wanted:

try ( readFile file ) >>= \res...

IO (Maybe a) and Maybe a are distinct

You have a function using IO (via readFile and try) but many of the cases do not return an IO result (Nothing and Just content).

Solution: Return via return Nothing or pure Nothing to lift a value into the IO monad.

The exception type was ambiguous

The try function can catch any exception type, just look at the signature:

try :: Exception e => IO a -> IO (Either e a)

When you totally ignore the exception you leave the type checker with no information to decide what e should be. In these situations an explicit type signature is useful, such as:

  Left (e::SomeException) -> pure Nothing

managagment is partial

managagment ["a","b"] is undefined as is any input list of length over one. Consider a final equational definition of:

managagment _ = managagment ["-h"]

Or more directly:

managagment _ = pure $ Just help

Style and other notes

  • managagment should probably management
  • Just (foo) is generally Just foo
  • help is not a function that returns a String. It is a value of type String.
  • The example was not complete, missing imports and help.

Fixed Code

Consider instead:

#!/usr/bin/env cabal
{- cabal:
    build-depends: base
-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE LambdaCase          #-}
import Control.Exception (try, SomeException)

main :: IO ()
main = print =<< management []

help :: String
help = "so helpful"

management :: [String] -> IO (Maybe String)
management [] = pure Nothing
management ["-h"] = pure $ Just help
management [file] =
    try (readFile file) >>=
      \case
         Left (e::SomeException) -> pure Nothing
         Right content -> pure $ Just content
management _ = pure $ Just help

And test as such:

% chmod +x x.hs
% ./x.hs

Upvotes: 1

Related Questions