<div class="gmail_quote">On 30 May 2011 05:05, Christopher Howard <span dir="ltr">&lt;<a href="mailto:christopher.howard@frigidcode.com">christopher.howard@frigidcode.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">

Hi. I&#39;m trying to learn Data.ConfigFile. I want to use the function<br>
readfile:<br>
<br>
[DESCRIPTION]<br>
readfile :: MonadError CPError m =&gt; ConfigParser -&gt; FilePath -&gt; IO (m<br>
ConfigParser)<br><br>
I understand that this function returns a monad, and I pull the value<br>
out of it with (&lt;-). And I believe this is similar to a &quot;Maybe&quot;<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&#39;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&#39;s understandable that actual usage isn&#39;t clear, it wasn&#39;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>λ&gt; do parser &lt;- readfile emptyCP &quot;../confy.conf&quot;; return (get (forceEither parser) &quot;PATHS&quot; &quot;upload_path&quot;) :: IO (Either CPError String)</div><div>Right &quot;uploads&quot;</div>

</div><div><br></div><div>Or you can get it within the monad like everything else:</div><div><br></div><div><div>λ&gt; do parser &lt;- readfile emptyCP &quot;../confy.conf&quot;; return (do config &lt;- parser; get config &quot;PATHS&quot; &quot;upload_path&quot;) :: IO (Either CPError String)</div>

<div>Right &quot;uploads&quot;</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>λ&gt; let getUploads ::  IO (Either CPError String); getUploads = runErrorT $ do parser &lt;- liftIO $ readfile emptyCP &quot;../confy.conf&quot;; config &lt;- parser; get config &quot;PATHS&quot; &quot;upload_path&quot; in getUploads</div>

<div>Right &quot;uploads&quot;</div></div><div><br></div><div>Or with join:</div><div><br></div><div><div>λ&gt; :t join</div><div>join :: (Monad m) =&gt; m (m a) -&gt; m a</div></div><div><div><div><div>λ&gt; let getUploads ::  IO (Either CPError String); getUploads = runErrorT $ do cp &lt;- join $ liftIO $ readfile emptyCP &quot;../confy.conf&quot;; get cp &quot;PATHS&quot; &quot;upload_path&quot; in getUploads</div>

<meta http-equiv="content-type" content="text/html; charset=utf-8"><div>Right &quot;uploads&quot;</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 (&lt;*&gt;) = ap; pure = return</div>

<div><br></div><div><div>λ&gt; let getCfg ::  IO (Either CPError (String,String));</div><div>       getCfg = runErrorT $ do</div><div>         cp &lt;- join $ liftIO $ readfile emptyCP &quot;../confy.conf&quot;;</div><div>

         (,) &lt;$&gt; get cp &quot;PATHS&quot; &quot;upload_path&quot;</div><div>             &lt;*&gt; get cp &quot;PATHS&quot; &quot;err_log&quot;</div><div>   in getCfg</div><div>Right (&quot;uploads&quot;,&quot;errors.log&quot;)</div>

</div></div>