[Haskell-beginners] Either Monadic Trouble

Daniel Fischer daniel.is.fischer at web.de
Tue Nov 10 10:13:52 EST 2009

Am Montag 09 November 2009 10:01:43 schrieb iæfai:
> With the below code, I am getting an error that I cannot resolve…

Everybody was so busy discussing whether Either (or rather (Either e)) is a monad that 
nobody looked at the code, so:

> Chess.hs:52:82:
>      Couldn't match expected type `Map [Char] [Char]'
>             against inferred type `Either ParseError ConfigMap'
>      In the third argument of `findWithDefault', namely `c'
>      In the `documentRoot' field of a record
>      In the first argument of `return', namely
>          `Config {documentRoot = (findWithDefault "web" "Document-
> Root" c)}'
> The specific code is:
> getConf :: FilePath -> IO (Either ParseError Config)
> getConf filePath
>      = return $ do
>          c <- readConfig filePath  -- (Either ParseError ConfigMap)

I believe the type of readConfig is

FilePath -> IO (Either ParseError ConfigMap)

, thus the binding of c, (c <-), still takes place in IO and c is one of (Left parseerror) 
or (Right configmap), hence c is not a suitable argument for findWithDefault.

>          return Config { documentRoot = Map.findWithDefault "web"
> "Document-Root" c }

The inner return also lives in IO, so had c a suitable type, your getConf would have type

FilePath -> IO (IO something).

I think you want 

getConf filePath = do
    r <- readConfig filePath
    return $ do
        c <- r       -- *now* we're using the monad (Either ParseError)
        return Config{ documentRoot = Map.findWithDefault "web" "Document-Root" c }

(if you have instance Monad (Either ParseError) in scope) or the equivalent using Pattern 
matching on the result of readConfig filePath.

> The type of c should be Either ParseError ConfigMap, which by my
> understanding of the Either monad would cause the c to be the Right
> side stripped, or skipped if Left.
> Full source for the module is below, and full project is hosted at
> http://patch-tag.com/r/iaefai/chess
> For some general information, I am replacing ConfigFile dependancy
> with a Parsec based config parser (I call it SimpleConfig) that suits
> my needs - it came from
> http://www.serpentine.com/blog/2007/01/31/parsing-a-simple-config-file-in-h
>askell/ originally and I modified it. On windows ConfigFile's dependancy on
> a posix regex library was causing trouble, so this is the effort to get rid
> of that dependancy.
> Any thoughts would be useful.
> There is one associated thought…
> The original function used to get configuration back to the program is
> -- Mostly from Chris Done's Blog
> getConf :: FilePath -> IO (Either (C.CPErrorData, String) Config)
> getConf filePath = runErrorT $ do
>      let cp = C.emptyCP { optionxform = id }
>      contents <- liftIO $ readFile filePath
>      config <- C.readstring cp contents
>      let get = C.get config "DEFAULT"
>      Config <$> get "Document-Root"
> I noted it used <$> and in the code that I retrieved originally from
> Chris Done's blog (no longer able to find it) used <*> for additional
> items. I would like some easy method of constructing the new Config
> structure in my new code, especially if it can be done without the
> record syntax like this thing gets away with. I am not sure how this
> thing associated "Document-Root" with documentRoot mind you.
> Thank you again.
> iæfai.

More information about the Beginners mailing list