<div dir="ltr"><br><br><div class="gmail_quote">On Mon, Oct 19, 2009 at 3:39 PM, Jose Iborra <span dir="ltr">&lt;<a href="mailto:pepeiborra@gmail.com">pepeiborra@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
You may want to take a look at anoother option in Hackage, the control-monad-exception package.<br>
<br>
<a href="http://pepeiborra.github.com/control-monad-exception/" target="_blank">http://pepeiborra.github.com/control-monad-exception/</a><br>
<br>
The control-monad-exception library provides the building blocks for<br>
<br>
 * Explicitly Typed exceptions (checked or not)<br>
 * which are composable<br>
 * and even provide stack traces (experimental feature)</blockquote><div><br>Jose,<br><br>Thank you very much, thinks looks like just the thing I was looking for. The only thing that slightly concerns me is the transformers dependency, but it&#39;s not a serious worry. I&#39;d love to try out the package right now, but with hackage being down I can&#39;t get the dependencies yet ;). I&#39;ll try it out as soon as I can.<br>
 <br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><div class="im"><br>
<br>
<br>
On 19/10/2009, at 01:00, Michael Snoyman wrote:<br>
<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
(Sorry, accidently took off cafe.)<br>
<br>
On Mon, Oct 19, 2009 at 12:44 AM, Henning Thielemann &lt;<a href="mailto:lemming@henning-thielemann.de" target="_blank">lemming@henning-thielemann.de</a>&gt; wrote:<br>
<br>
On Mon, 19 Oct 2009, Michael Snoyman wrote:<br>
<br>
Does the explicit-exception package provide what you need?<br>
<br>
<a href="http://hackage.haskell.org/package/explicit-exception" target="_blank">http://hackage.haskell.org/package/explicit-exception</a><br>
<br>
<br>
I don&#39;t think so, but correct me if I&#39;m wrong. I want to make it easy to chain together<br>
computations which could fail in different ways. For example, something like this:<br>
<br>
attemptReadInt :: String -&gt; Attempt Int<br>
attemptLookup :: String -&gt; [(String, String)] -&gt; Attempt String<br>
attemptLookupInt :: String -&gt; [(String, String)] -&gt; Attempt Int<br>
attemptLookupInt k m = attemptLookup k m &gt;&gt;= attemptReadInt<br>
<br>
Now, in the explicit-exception package, I could- in this simple example- define<br>
something like:<br>
<br>
data MyErrors = KeyNotFound | InvalidInt<br>
<br>
<br>
type Attempt = Exceptional MyErrors<br>
<br>
True; that&#39;s what I meant by I could do this in my simple example.<br>
<br>
<br>
But this solution would not scale.<br>
<br>
You want to add other exceptions? The idea of my package is to make exceptions explicit in the type. Otherwise you would use extensible-exceptions. Or you could define MyErrors using an existential type.<br>
<br>
Which is my point. I&#39;m trying to provide a package for non-explicit exceptions. To compare to other programming languages, I think your package is providing the equivalent of Java checked exceptions, while mine is providing (safe) unchecked exceptions. I say safe because you still need to explicitly decide to turn an Attempt into a possible runtime exception which will bring down your program.<br>

<br>
Defining MyErrors using an existential type would essentially recreate the entire attempt package; I don&#39;t see that purpose in everyone wanted unchecked exceptions needing to reinvent the wheel in non-compatible ways. If multiple libraries use attempt, they can easily have their possible-error-returning functions chain together safely.<br>

<br>
</blockquote>
<br></div>
I believe that control-monad-exception solves this tension between composability and explicit exceptions.<br>
You can have explicit exceptions which are composable:<br>
<br>
  &gt; data DivideByZero = DivideByZero deriving (Show, Typeable)<br>
  &gt; data SumOverflow  = SumOverflow  deriving (Show, Typeable)<br>
<br>
  &gt; instance Exception DivideByZero<br>
  &gt; instance Exception SumOverflow<br>
<br>
  &gt; data Expr = Add Expr Expr | Div Expr Expr | Val Double<br>
<br>
  &gt; eval (Val x)     = return x<br>
  &gt; eval (Add a1 a2) = do<br>
  &gt;    v1 &lt;- eval a1<br>
  &gt;    v2 &lt;- eval a2<br>
  &gt;    let sum = v1 + v2<br>
  &gt;    if sum &lt; v1 || sum &lt; v2 then throw SumOverflow else return sum<br>
  &gt; eval (Div a1 a2) = do<br>
  &gt;    v1 &lt;- eval a1<br>
  &gt;    v2 &lt;- eval a2<br>
  &gt;    if v2 == 0 then throw DivideByZero else return (v1 / v2)<br>
<br>
  GHCi infers the following types<br>
<br>
  &gt; :t eval<br>
  &gt;   eval :: (Throws DivideByZero l, Throws SumOverflow l) =&gt; Expr -&gt; EM l Double<br>
<br>
  &gt; :t eval `catch` \ (e::DivideByZero) -&gt; return (-1)<br>
  &gt;  .... :: Throws SumOverflow l =&gt; Expr -&gt; EM l Double<br>
<br>
  &gt; :t runEM(eval `catch` \ (e::SomeException) -&gt; return (-1))<br>
  &gt;  .... : Expr -&gt; Double<div class="im"><br>
<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>
Additionally, there&#39;s two immediate features I think I would miss from my package:<br>
<br>
1) fail works properly, so an Attempt would be a valid monad response from people who<br>
use that function.<br>
<br>
As far as I understand, &#39;fail&#39; is used/abused for reporting failed pattern matches in do notation. If a failed pattern match indicates a programming error, it should be a really error, and not something that must be handled at run-time.<br>

<br>
That&#39;s a lot of very debateable statements you just made. It might be that it&#39;s strongly encouraged to only use fail for failed pattern matching, but in practice you could use it for any monadic failure. Also, there&#39;s nothing stopping a user from re-throwing pattern match exceptions received in an Attempt.<br>

</blockquote>
<br></div>
I am with Henning on &#39;fail&#39;.<br>
It must not be used as a replacement for throw, only for failed pattern matches which are programming errors and thus unchecked exceptions.<br>
</blockquote></div><br>I&#39;m not arguing how it *should* be used, I&#39;m arguing how it *might* be used, and I think calling error is not appropriate. An unchcked exception which can be caught if necesary (I&#39;m assuming that&#39;s what runEMParanoid does) sounds like that right thing.<br>
<br>Michael<br></div>