<div class="gmail_quote">On 30 May 2011 05:05, Christopher Howard <span dir="ltr"><<a href="mailto:christopher.howard@frigidcode.com">christopher.howard@frigidcode.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
Hi. I'm trying to learn Data.ConfigFile. I want to use the function<br>
readfile:<br>
<br>
[DESCRIPTION]<br>
readfile :: MonadError CPError m => ConfigParser -> FilePath -> IO (m<br>
ConfigParser)<br><br>
I understand that this function returns a monad, and I pull the value<br>
out of it with (<-). And I believe this is similar to a "Maybe"<br>
situation where I can do one thing if it provides a syntax error and<br>
another thing if it provides the ConfigParser. But I'm not sure what<br>
this would look like in actual code. Could somebody give me a small,<br>
simple example?<br></blockquote><div><br></div><div>It's understandable that actual usage isn't clear, it wasn't clear to me either when I first encountered it. There are a few ways to use it. It returns an instance of error Monad, so you can either force it into an Either value:</div>
<div><br></div><div><div>λ> do parser <- readfile emptyCP "../confy.conf"; return (get (forceEither parser) "PATHS" "upload_path") :: IO (Either CPError String)</div><div>Right "uploads"</div>
</div><div><br></div><div>Or you can get it within the monad like everything else:</div><div><br></div><div><div>λ> do parser <- readfile emptyCP "../confy.conf"; return (do config <- parser; get config "PATHS" "upload_path") :: IO (Either CPError String)</div>
<div>Right "uploads"</div></div><div><br></div><div>Because it returns any MonadError instance, and IO is an instance of MonadError, you can skip the double level of monadery:</div><div><br></div><div><div>λ> let getUploads :: IO (Either CPError String); getUploads = runErrorT $ do parser <- liftIO $ readfile emptyCP "../confy.conf"; config <- parser; get config "PATHS" "upload_path" in getUploads</div>
<div>Right "uploads"</div></div><div><br></div><div>Or with join:</div><div><br></div><div><div>λ> :t join</div><div>join :: (Monad m) => m (m a) -> m a</div></div><div><div><div><div>λ> let getUploads :: IO (Either CPError String); getUploads = runErrorT $ do cp <- join $ liftIO $ readfile emptyCP "../confy.conf"; get cp "PATHS" "upload_path" in getUploads</div>
<meta http-equiv="content-type" content="text/html; charset=utf-8"><div>Right "uploads"</div></div></div></div><div><br></div><div>Control.Applicative also works nicely for this.</div><div><br></div><div>instance Applicative (ErrorT CPError IO) where (<*>) = ap; pure = return</div>
<div><br></div><div><div>λ> let getCfg :: IO (Either CPError (String,String));</div><div> getCfg = runErrorT $ do</div><div> cp <- join $ liftIO $ readfile emptyCP "../confy.conf";</div><div>
(,) <$> get cp "PATHS" "upload_path"</div><div> <*> get cp "PATHS" "err_log"</div><div> in getCfg</div><div>Right ("uploads","errors.log")</div>
</div></div>