
Ah, I see. Even if you desugar pattern matching against (_, _) in a do block like you do for multi-constructor data types, ⊥ still does not result in an invocation of fail, since matching ⊥ against (_, _) leads to divergence. To illustrate this, let f be defined as follows: f (_, _) = True f _ = False Applying f to an expression of the form (x, y) results in True, applying it to ⊥ results in ⊥. False can never be the result. That said, it would seem more logical to me if all data types would be treated equal in monadic pattern matching. All the best, Wolfgang Am Donnerstag, den 11.06.2015, 11:36 -0400 schrieb David Feuer:
Pattern matching on `undefined` is not like pattern match failure. Single-constructor types are only special if they're unlifted: `newtype` and GHC's unboxed tuples are the only examples I know of, and you can't use unboxed tuples in this context.
On Thu, Jun 11, 2015 at 11:28 AM, Wolfgang Jeltsch
wrote: Are you sure that desugaring works this way? If yes, this should be considered a bug and be fixed, I would say. It is very illogical.
All the best, Wolfgang
Am Donnerstag, den 11.06.2015, 16:23 +0100 schrieb David Turner:
AIUI the point about ⊥ and (⊥, ⊥) being different doesn't matter here: a bind for a single-constructor datatype never desugars in a way that uses fail (which isn't to say that it can't be undefined)
For instance:
runErrorT (do { (_,_) <- return undefined; return () } :: ErrorT String IO ())
throws an exception, even though the bind is in ErrorT where fail just returns left:
runErrorT (do { fail "oops"; return () } :: ErrorT String IO ())
=> Left "oops"
Hope that helps, and hope I understand correctly!
David
On 11 June 2015 at 16:08, Wolfgang Jeltsch
wrote: Hi David,
thank you very much for this proposal. I think having fail in Monad is just plain wrong, and I am therefore very happy to see it being moved out.
I have some remarks, though:
A class of patterns that are conditionally failable are `newtype`s, and single constructor `data` types, which are unfailable by themselves, but may fail if matching on their fields is done with failable paterns.
The part about single-constructor data types is not true. A single-constructor data type has a value ⊥ that is different from applying the data constructor to ⊥’s. For example, ⊥ and (⊥, ⊥) are two different values. Matching ⊥ against the pattern (_, _) fails, matching (⊥, ⊥) against (_, _) succeeds. So single-constructor data types are not different from all other data types in this respect. The dividing line really runs between data types and newtypes. So only matches against patterns C p where C is a newtype constructor and p is unfailable should be considered unfailable.
- Applicative `do` notation is coming sooner or later, `fail` might be useful in this more general scenario. Due to the AMP, it is trivial to change the `MonadFail` superclass to `Applicative` later. (The name will be a bit misleading, but it's a very small price to pay.)
I think it would be very misleading having a MonadFail class that might have instances that are not monads, and that this is a price we should not pay. So we should not name the class MonadFail. Maybe, Fail would be a good name.
I think we should keep the `Monad` superclass for three main reasons:
- We don't want to see `(Monad m, MonadFail m) =>` all over the place.
But exactly this will happen if we change the superclass of (Monad)Fail from Monad to Applicative. So it might be better to impose a more light-weight constraint in the first place. Functor m might be a good choice.
All the best, Wolfgang
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries