#4159: move Monad and MonadFix instances for Either from mtl to base

The proposal is to move the Monad and MonadFix instances for Either (currently in the mtl package) to Control.Monad.Instances and Control.Monad.Fix respectively (both in the base package). The Monad instance is still an orphan, to retain Haskell 98 compatibility, but the MonadFix instance is together with its class. The Error constraint is removed from both instances, and the default definition of fail is used. Discussion deadline: 20th July 2010

Excerpts from Ross Paterson's message of Tue Jun 29 05:26:49 -0400 2010:
The proposal is to move the Monad and MonadFix instances for Either (currently in the mtl package) to Control.Monad.Instances and Control.Monad.Fix respectively (both in the base package). The Monad instance is still an orphan, to retain Haskell 98 compatibility, but the MonadFix instance is together with its class. The Error constraint is removed from both instances, and the default definition of fail is used.
+1, and long overdue, I think. Cheers, Edward

On Tue, 29 Jun 2010, Edward Z. Yang wrote:
Excerpts from Ross Paterson's message of Tue Jun 29 05:26:49 -0400 2010:
The proposal is to move the Monad and MonadFix instances for Either (currently in the mtl package) to Control.Monad.Instances and Control.Monad.Fix respectively (both in the base package). The Monad instance is still an orphan, to retain Haskell 98 compatibility, but the MonadFix instance is together with its class. The Error constraint is removed from both instances, and the default definition of fail is used.
+1, and long overdue, I think.
+1

On Tue, Jun 29, 2010 at 11:26 AM, Ross Paterson
The proposal is to move the Monad and MonadFix instances for Either (currently in the mtl package) to Control.Monad.Instances and Control.Monad.Fix respectively
+1 (I assume the 'fail' method will keep its default definition of 'error'.) Regards, Bas

+1, and I'd vote again if I could!
On Tue, Jun 29, 2010 at 5:26 AM, Ross Paterson
The proposal is to move the Monad and MonadFix instances for Either (currently in the mtl package) to Control.Monad.Instances and Control.Monad.Fix respectively (both in the base package). The Monad instance is still an orphan, to retain Haskell 98 compatibility, but the MonadFix instance is together with its class. The Error constraint is removed from both instances, and the default definition of fail is used.
Discussion deadline: 20th July 2010 _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 6/29/10 05:26 , Ross Paterson wrote:
The proposal is to move the Monad and MonadFix instances for Either (currently in the mtl package) to Control.Monad.Instances and Control.Monad.Fix respectively (both in the base package). The Monad
+1 - -- brandon s. allbery [linux,solaris,freebsd,perl] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.10 (Darwin) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkwp7ikACgkQIn7hlCsL25WDRACgzgMEsfH4tG0DWRiiqRRrKle0 7QAAnjWyTydOlju3v097QbLhdNPznYsg =Ls3P -----END PGP SIGNATURE-----

2010/6/29 Ross Paterson
The proposal is to move the Monad and MonadFix instances for Either (currently in the mtl package) to Control.Monad.Instances and Control.Monad.Fix respectively (both in the base package). The Monad instance is still an orphan, to retain Haskell 98 compatibility, but the MonadFix instance is together with its class. The Error constraint is removed from both instances, and the default definition of fail is used.
+1 David

"Ross Paterson"
The proposal is to move the Monad and MonadFix instances for Either (currently in the mtl package) to Control.Monad.Instances and Control.Monad.Fix respectively (both in the base package). The Monad instance is still an orphan, to retain Haskell 98 compatibility, but the MonadFix instance is together with its class. The Error constraint is removed from both instances, and the default definition of fail is used.
Discussion deadline: 20th July 2010
-1, because the default definition of fail is error, which would render the Monad instance useless (unless I'm missing something?). This has never been the Monad instance I wanted for Either (I only use Either if I care about both alternatives, and fail=error would spoil that), nor do I think that there is a single generally useful instance that would improve the existing one in mtl: 0 defining 'instance Fail a => Monad (Either a)' would prevent any instances; but sometimes, Monad (Either String) is useful, so this is no good 1 leaving out the instance would let me define my own; but so could everyone else, so conflicts loom - again, no good 2a I don't like the Error constraint, but I can live with it (almost, because even two libs defining the same instance result in conflict); doesn't work in the long term 2b just moving the existing instance unchanged from Control.Monad.Error into Control.Monad.Instances might be an acceptable improvement 3a limiting the Monad instance to (Either String) with fail as Left would cover the only variant of Monad (Either a) that I've actually used myself; this is no good if there are actually any other Monad (Either a) instances in use 3b even 'fail s = Left (error s)' would be preferable to 'fail = error', if you insist on dropping Error; but no good, that would take away programmer choice (and prevent my only use case!) 4 using 'fail = error' is the worst of all choices, and certainly shouldn't be moved in a position where I cannot avoid it (the other instances in Control.Monad.Instances are occasionally useful, this one wouldn't be); this is also inconsistent with the existing Monad Maybe instance, and doesn't tie in with MonadPlus (Either e): whenever possible, fail s should be mzero; this is no good at all. Of these, only 2b seems acceptable, helping to prevent conflicting equivalent instances for the only use case I've encountered, Monad (Either String). 3b can be recovered from 2b (noMsg defaults to strMsg "", strMsg defaults to const noMsg; one could change the default of strMsg to error, to preserve the error message). In other words, the current design is annoying, but not nearly as bad as the alternatives - the only improvements would be to move the instances out of mtl, to avoid conflicts, and perhaps to change the default of strMsg. Claus

On Tue, 29 Jun 2010, Claus Reinke wrote:
"Ross Paterson"
schrieb im Newsbeitrag news:20100629092649.GA3460@soi.city.ac.uk... The proposal is to move the Monad and MonadFix instances for Either (currently in the mtl package) to Control.Monad.Instances and Control.Monad.Fix respectively (both in the base package). The Monad instance is still an orphan, to retain Haskell 98 compatibility, but the MonadFix instance is together with its class. The Error constraint is removed from both instances, and the default definition of fail is used.
Discussion deadline: 20th July 2010
-1, because the default definition of fail is error, which would render the Monad instance useless (unless I'm missing something?).
You would just use Left instead of 'fail' if you want to show failure in an Either value.

The proposal is to move the Monad and MonadFix instances for Either (currently in the mtl package) to Control.Monad.Instances and Control.Monad.Fix respectively (both in the base package). The Monad instance is still an orphan, to retain Haskell 98 compatibility, but the MonadFix instance is together with its class. The Error constraint is removed from both instances, and the default definition of fail is used.
-1, because the default definition of fail is error, which would render the Monad instance useless (unless I'm missing something?).
You would just use Left instead of 'fail' if you want to show failure in an Either value.
a) you are suggesting to bypass a method of the proposed Monad instance because it isn't useful, I am suggesting not to define a Monad instance with unusable methods b) desugaring of pattern-match failure in Monads calls fail, not Left Claus PS. I just remembered that I have used 'Monad (Either a)', for 'a' other than String (a parser with error information in addition to plain error message). That application didn't use Control.Monad.Errror or Control.Monad.Instances - it could have been made to fit the current Control.Monad.Error design but not the proposed design, because it relied on 'fail s `mplus` return x == return x'.

On Tue, Jun 29, 2010 at 6:13 PM, Claus Reinke
The proposal is to move the Monad and MonadFix instances for Either
(currently in the mtl package) to Control.Monad.Instances and Control.Monad.Fix respectively (both in the base package). The Monad instance is still an orphan, to retain Haskell 98 compatibility, but the MonadFix instance is together with its class. The Error constraint is removed from both instances, and the default definition of fail is used.
-1, because the default definition of fail is error, which would render the Monad instance useless (unless I'm missing something?).
You would just use Left instead of 'fail' if you want to show failure in an Either value.
a) you are suggesting to bypass a method of the proposed Monad instance because it isn't useful, I am suggesting not to define a Monad instance with unusable methods b) desugaring of pattern-match failure in Monads calls fail, not Left
Claus
PS. I just remembered that I have used 'Monad (Either a)', for 'a' other than String (a parser with error information in addition to plain error message). That application didn't use Control.Monad.Errror or Control.Monad.Instances - it could have been made to fit the current Control.Monad.Error design but not the proposed design, because it relied on 'fail s `mplus` return x == return x'.
A reasonable case can be made for the existence of a monad that does something useful with fail. I don't think that that monad should be Either. 'Either' takes on the connotation of being the 'sum type' for the category of Haskell types. This sum type has a very well formed and simple monad, that has a lot of useful theoretical properties, and is useful in a strictly larger array of scenarios than the monad with the error constraint, with the one notable exception that it doesn't handle the 'fail' property that was bolted into Monad in Haskell 98. The obvious name for such a monad would be Error, to go with ErrorT, but the Error class conflicts with that name, but perhaps: data Fail e a = Error e | OK a would be worth adding to Control.Monad.Error, during the same general timetable as this change, to provide users who really want the existing mtl Either semantics an upgrade path. In the interest of not killing this proposal with bikeshedding concerns over what to call it (Fail, Err, Error, etc), we should probably put that forward as a completely separate libraries proposal though. It would address the confusion caused to new users who often on #haskell ask why 'Left' is the error case, and would address your use case explicitly, and even less verbosely. ;) -Edward Kmett

On Tue, 29 Jun 2010, Edward Kmett wrote:
A reasonable case can be made for the existence of a monad that does something useful with fail. I don't think that that monad should be Either.
'Either' takes on the connotation of being the 'sum type' for the category of Haskell types. This sum type has a very well formed and simple monad, that has a lot of useful theoretical properties, and is useful in a strictly larger array of scenarios than the monad with the error constraint, with the one notable exception that it doesn't handle the 'fail' property that was bolted into Monad in Haskell 98.
The obvious name for such a monad would be Error, to go with ErrorT, but the Error class conflicts with that name, but perhaps:
data Fail e a = Error e | OK a
would be worth adding to Control.Monad.Error, during the same general timetable as this change, to provide users who really want the existing mtl Either semantics an upgrade path.
In the interest of not killing this proposal with bikeshedding concerns over what to call it (Fail, Err, Error, etc), we should probably put that forward as a completely separate libraries proposal though.
It would address the confusion caused to new users who often on #haskell ask why 'Left' is the error case, and would address your use case explicitly, and even less verbosely. ;)
+1

A reasonable case can be made for the existence of a monad that does something useful with fail. I don't think that that monad should be Either.
I don't mean to further derail the proposal, which I think is a worthy one, but what's the feeling on a complete deprecation of 'fail' and making 'pat <- ...' the same as 'let pat = ...'? I've never used it, not because I've never come across a case where it would be useful, but that I don't trust to remember the behaviour of 'fail' for this particular monad and even if I do, maybe my reader doesn't. So I prefer 'case xyz of { pat -> mzero/throw/whatever }'. It's more wordy but clearer. Are there uses out there that really rely on the conciseness afforded by refutable patterns?

The current proposal is not trying to fix the fail situation, so this is a bit off topic, but to answer your question:
So I prefer 'case xyz of { pat -> mzero/throw/whatever }'. It's more wordy but clearer. Are there uses out there that really rely on the conciseness afforded by refutable patterns?
The stand-alone alternative is more like do { p1 <- return x; return e1 } vs case x of { p1 -> return e1; _ -> mzero} which doesn't look much worse until you realize that the former embeds nicely into existing monadic code, the latter doesn't. So it becomes do { ..; p1 <- return x; .. } vs do { ..; case x of { p1 -> ..; _ -> mzero } } and so on for every added pattern. When I embed Haskell-Coloured Petri Nets in Haskell, the former style can be made to resemble the input language quite closely (changing from graphical to textual representation, but with easily recognizable structure). When writing combinator parsers, type system rules, or other rule-based embedded languages that embed into a MonadPlus, it can be similarly helpful to write down only the interesting success cases, without messing up the code with standard failure cases. Claus

On Wed, Jun 30, 2010 at 4:57 PM, Claus Reinke
The current proposal is not trying to fix the fail situation, so this is a bit off topic, but to answer your question:
So I prefer 'case xyz of { pat -> mzero/throw/whatever }'. It's more
wordy but clearer. Are there uses out there that really rely on the conciseness afforded by refutable patterns?
The stand-alone alternative is more like
do { p1 <- return x; return e1 } vs case x of { p1 -> return e1; _ -> mzero}
which doesn't look much worse until you realize that the former embeds nicely into existing monadic code, the latter doesn't. So it becomes
do { ..; p1 <- return x; .. }
vs
do { ..; case x of { p1 -> ..; _ -> mzero } }
and so on for every added pattern. When I embed Haskell-Coloured Petri Nets in Haskell, the former style can be made to resemble the input language quite closely (changing from graphical to textual representation, but with easily recognizable structure).
And you can have these semantics, just tied to another monad with nice names for the different form, which is clearer about being a monad for handling errors.
When writing combinator parsers, type system rules, or other rule-based embedded languages that embed into a MonadPlus, it can be similarly helpful to write down only the interesting success cases, without messing up the code with standard failure cases.
I'm not making the case for killing fail in general here. I merely agree with Ross that the right call is to remove the spurious constraint on Either. I wholeheartedly support the creation of another monad with suitable semantics for your purposes. -Edward Kmett Claus
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

The proposal is to move the Monad and MonadFix instances for Either (currently in the mtl package) to Control.Monad.Instances and Control.Monad.Fix respectively (both in the base package). The Monad instance is still an orphan, to retain Haskell 98 compatibility, but the MonadFix instance is together with its class. The Error constraint is removed from both instances, and the default definition of fail is used.
-1, because the default definition of fail is error, which would render the Monad instance useless (unless I'm missing something?).
Note that my opposition is against making 'Monad (Either a)' less defined and less tunable than it is at the moment. One could also wonder whether the instance should be in Data.Either (the instance for Maybe is in Data.Maybe), whether mtl should simply be changed to use something other than Either, so that mtl's Either-variant and its MonadError instances could remain together, or what the effect of removing Error and moving the 'Monad (Either a)' instance would be on the remainder of mtl's code. To those '+1' fans: please compare what the proposal actually does to what you would like to see. Most of us have had bad experiences with these instances or with Haskell's instance import behaviour (my own complaints go back to 2003 or so). So most of us are happy to see something move. But fixing a less defined 'Monad (Either a)' instance even higher in the package hierarchy is not going to help. Do Ross and us all a favour and study his proposal and the consequences before voting. |A reasonable case can be made for the existence of a monad that does |something useful with fail. Every Monad should try to do its best with fail. If, at some point, fail in Monad gets replaced with throwError in MonadError, or with mzero in MonadZero, or with something else, we can ignore fail in Monad, but I would still expect pattern match error via fail to integrate well with at least one of MonadPlus or MonadError. |I don't think that that monad should be Either. |'Either' takes on the connotation of being the 'sum type' for the category |of Haskell types. This sum type has a very well formed and simple monad, |that has a lot of useful theoretical properties, and is useful in a strictly |larger array of scenarios than the monad with the error constraint, with |the one notable exception that it doesn't handle the 'fail' property that |was bolted into Monad in Haskell 98. Remember that we are talking about Haskell, not category theory. If you want to define a duplicate of Either with additional properties, go ahead. But don't forget to duplicate the existing Either libraries. If Haskell had parameterized modules, we could pass our choice of Either-alternative to both mtl's modules and Either libraries, and everone could be happy. As long as we don't have that option, I don't see why Haskell's sum type cannot have a useful fail. If you are just concerned about the Error constraint, simply provide a default instance that maps strMsg to error (see example of default instances with user override in base Data.Typable). That way, you'd get 'Monad (Either a)' without Error constraint, but with strictly more defined fail ('Left _|_' instead of '_|_'), and others can add even more defined fail when needed. If you are concerned about something else, please explain how a less defined instance in Control.Monad.Instances is going to address your concern in a way a more defined instance cannot. Claus

On Wed, Jun 30, 2010 at 09:36:00AM +0200, Claus Reinke wrote:
Note that my opposition is against making 'Monad (Either a)' less defined and less tunable than it is at the moment.
It's a common trade-off: the Error constraint limits the instances that are available, but gives you a bit more when you have an instance. One must weigh the relative value of fail vs the unconstrained instance.
One could also wonder whether the instance should be in Data.Either (the instance for Maybe is in Data.Maybe), [...]
The problem with that is that Haskell 98 does not define such an instance, so a legal Haskell98 module that defined an instance itself would be broken by an instance in a module imported by the Prelude.
If you are just concerned about the Error constraint, simply provide a default instance that maps strMsg to error (see example of default instances with user override in base Data.Typable). That way, you'd get 'Monad (Either a)' without Error constraint, but with strictly more defined fail ('Left _|_' instead of '_|_'), and others can add even more defined fail when needed.
Do you mean an overlapping instance? There are problems with that too.

Note that my opposition is against making 'Monad (Either a)' less defined and less tunable than it is at the moment.
It's a common trade-off: the Error constraint limits the instances that are available, but gives you a bit more when you have an instance. One must weigh the relative value of fail vs the unconstrained instance.
If there is no full definition of 'Monad (Either a)' for all 'a', then qualifying 'a' by an additional type class seems to be the standard Haskell solution. As I said, even if you just want to drop 'Error', you could define 'fail s = Left (error s)'. That would still be less defined than the current instance, but more defined than the proposed instance. So you've deliberately chosen not to use 'Left' and not to represent 'fail' in the data type.
If you are just concerned about the Error constraint, simply provide a default instance that maps strMsg to error (see example of default instances with user override in base Data.Typable). That way, you'd get 'Monad (Either a)' without Error constraint, but with strictly more defined fail ('Left _|_' instead of '_|_'), and others can add even more defined fail when needed.
Do you mean an overlapping instance? There are problems with that too.
Yes to both. But it would avoid the problems with the unconstrained Monad instance for Either a, wouldn't it? And most of the time, neither the OverlappingInstances nor the Error constraint would be visible to client code, while the 'fail = error' default would be quite visible (with your instance version, none of the Either lines in client.hs below would return any information before throwing the error). Claus ----------------------- Lib.hs {-# LANGUAGE OverlappingInstances #-} {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE FlexibleInstances #-} module Lib where import Control.Monad class Error a where strMsg :: String -> a instance Error String where strMsg = id instance Error a where strMsg = error instance Error a => Monad (Either a) where Left l >>= _ = Left l Right r >>= f = f r return = Right fail = Left . strMsg instance Error a => MonadPlus (Either a) where mzero = Left (strMsg "mzero") Left _ `mplus` x = x Right r `mplus` _ = Right r --------------------client.hs import Lib import Control.Monad x,y,z :: MonadPlus m => m Int x = do 1 <- return 2; return 21 y = do 2 <- return 2; return 42 z = x `mplus` y main = do print (z::Maybe Int) print (x::Maybe Int) print (z::[Int]) print (x::[Int]) print (z::Either String Int) print (z::Either Bool Int) print (x::Either String Int) print (x::Either Bool Int) ----------------- output *Main> main Just 42 Nothing [42] [] Right 42 Right 42 Left "Pattern match failure in do expression at .. client.hs:5:7" Left *** Exception: Pattern match failure in do expression at .. client.hs:5:7

On Thu, Jul 01, 2010 at 12:29:57AM +0200, Claus Reinke wrote:
As I said, even if you just want to drop 'Error', you could define 'fail s = Left (error s)'. That would still be less defined than the current instance, but more defined than the proposed instance.
That didn't occur to me -- it seems harmless enough, but it wouldn't be enough to support pattern binding with the Either monad, would it?
Do you mean an overlapping instance? There are problems with that too.
Yes to both. But it would avoid the problems with the unconstrained Monad instance for Either a, wouldn't it?
It seems disproportionate: Either is a Prelude type, and it seems reasonable to stick to the core language in defining its instances of Prelude classes. One can always use a new type for the Error thing.

On Wed, Jun 30, 2010 at 11:57:23PM +0100, Ross Paterson wrote:
On Thu, Jul 01, 2010 at 12:29:57AM +0200, Claus Reinke wrote:
As I said, even if you just want to drop 'Error', you could define 'fail s = Left (error s)'. That would still be less defined than the current instance, but more defined than the proposed instance.
That didn't occur to me -- it seems harmless enough, but it wouldn't be enough to support pattern binding with the Either monad, would it?
Please no, there is no reason to associate Left with failure of any sort in the either instance. Either is the perfectly useful monad of a computation with a short circuit return, the short circuit return doesn't necessarily have anything to do with failure, any attempt to conflate the two would be artificial and limiting. John -- John Meacham - ⑆repetae.net⑆john⑈ - http://notanumber.net/

On Wed, Jun 30, 2010 at 6:57 PM, Ross Paterson
On Thu, Jul 01, 2010 at 12:29:57AM +0200, Claus Reinke wrote:
As I said, even if you just want to drop 'Error', you could define 'fail s = Left (error s)'. That would still be less defined than the current instance, but more defined than the proposed instance.
That didn't occur to me -- it seems harmless enough, but it wouldn't be enough to support pattern binding with the Either monad, would it?
I think it would be. -Edward Kmett

I can't decide if I like the fail s = error s or fail s = Left (error
s) behaviour better, and I'd prefer if we could put whatever we decide
upon in the Prelude, but +1 for the proposal overall. I'd also like
the function instances of Functor and Monad in the Prelude, for that
matter.
- Cale
On 30 June 2010 19:25, Edward Kmett
On Wed, Jun 30, 2010 at 6:57 PM, Ross Paterson
wrote: On Thu, Jul 01, 2010 at 12:29:57AM +0200, Claus Reinke wrote:
As I said, even if you just want to drop 'Error', you could define 'fail s = Left (error s)'. That would still be less defined than the current instance, but more defined than the proposed instance.
That didn't occur to me -- it seems harmless enough, but it wouldn't be enough to support pattern binding with the Either monad, would it?
I think it would be. -Edward Kmett _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

As I said, even if you just want to drop 'Error', you could define 'fail s = Left (error s)'. That would still be less defined than the current instance, but more defined than the proposed instance. That didn't occur to me -- it seems harmless enough, but it wouldn't be enough to support pattern binding with the Either monad, would it?
Only partially - sufficient to use it for MonadPlus mzero composition or for MonadError early exit, but not sufficient to make use of the error information (essentially, we model 'Either Void b' on 'Maybe b'). The alternative provided in mtl additionally allows us to embed the error information in whatever type we use for Left (via a custom Error instance). Quite a bit of thought must have gone into the mtl design there, which is why it makes me sad that so many are willing to throw that away without discussion, and without equivalent alternatives. The alternative I gave in the example code keeps these possibilities while also providing a default instance for Error (for people who do not want to bother defining their own). The use of Overlapping Instances should be limited to the defining module (unless you want to define your custom instance for Error for a use of Either that would not be possible in the original proposal), but might have other issues - I'd be interested to hear about them. I realize now that there are uses that wouldn't be served by this alternative, because they are incompatible with established use in mtl. Obviously, I am against replacing an instance that has been incompatible with those new uses with an instance that would be incompatible with old uses. I thought this proposal was about reducing conflicts between mtl alternatives and their clients, by moving the instance up in the package hierarchy. That would be something I agree with. I also agree that the source of trouble is in forcing fail into Monad, but until that is changed, we're stuck with it. And If the current proposal is about changing the instance in breaking (and, given Haskell's limitations, non-fixable) ways, then I am no longer opposed just on details, but on principle: those who want Either with different uses should use a different Either-like type.
Do you mean an overlapping instance? There are problems with that too.
Yes to both. But it would avoid the problems with the unconstrained Monad instance for Either a, wouldn't it?
It seems disproportionate: Either is a Prelude type, and it seems reasonable to stick to the core language in defining its instances of Prelude classes. One can always use a new type for the Error thing.
There is a good reason that Either does not have a Monad instance in the Prelude. To make an instance that serves most uses, one needs additional tools (the mtl solution uses few tools, so would fit your requirements, but has an annoying extra constraint; the OverlappingInstances solution lets us avoid that constraint, and there is a precedent for this kind of use in base). And yes, mtl should have used and should use some other type for its Error thing. And the current proposal is headed to repeat that mistake, by fixing Either's Monad to one class of uses. Only that the proposal's instance has a narrower class of uses(*), and a wider exposure of the problematic instance. But I have already cast my one vote, and I've tried to highlight the issues and alternatives. Claus (*) Haskellers who don't use fail, explicitly or implicitly, should not be bothered by a fail that tries to map error messages to their Left type (fail :: Error a => Either a b), but Haskellers who do use fail (mostly implicitly) are stuck if fail is error.

On Thu, Jul 01, 2010 at 11:18:22AM +0200, Claus Reinke wrote:
As I said, even if you just want to drop 'Error', you could define 'fail s = Left (error s)'. That would still be less defined than the current instance, but more defined than the proposed instance. That didn't occur to me -- it seems harmless enough, but it wouldn't be enough to support pattern binding with the Either monad, would it?
Only partially - sufficient to use it for MonadPlus mzero composition or for MonadError early exit, but not sufficient to make use of the error information (essentially, we model 'Either Void b' on 'Maybe b').
I thought so -- that functionality is already available in the Monad instance for Maybe.
those who want Either with different uses should use a different Either-like type.
I think we all agree on that. (We only differ on whose are the "different uses".)

On Wed, Jun 30, 2010 at 6:29 PM, Claus Reinke
Note that my opposition is against making 'Monad (Either a)' less
defined and less tunable than it is at the moment.
It's a common trade-off: the Error constraint limits the instances that are available, but gives you a bit more when you have an instance. One must weigh the relative value of fail vs the unconstrained instance.
If there is no full definition of 'Monad (Either a)' for all 'a', then qualifying 'a' by an additional type class seems to be the standard Haskell solution. As I said, even if you just want to drop 'Error', you could define 'fail s = Left (error s)'. That would still be less defined
Actually, I rather like this option. =) -Edward Kmett

Excerpts from Claus Reinke's message of Wed Jun 30 03:36:00 -0400 2010:
Every Monad should try to do its best with fail. If, at some point, fail in Monad gets replaced with throwError in MonadError, or with mzero in MonadZero, or with something else, we can ignore fail in Monad, but I would still expect pattern match error via fail to integrate well with at least one of MonadPlus or MonadError.
I respectfully disagree. It is far too easy to use fail in a stack of monad transformers and end up using the wrong instance and getting error "message" semantics; it is far safer to use the appropriate MonadPlus function. fail is a disaster, from both an engineering and theoretical standpoint, and I cannot in good conscious recommend that people use it. Cheers, Edward

Every Monad should try to do its best with fail. If, at some point, fail in Monad gets replaced with throwError in MonadError, or with mzero in MonadZero, or with something else, we can ignore fail in Monad, but I would still expect pattern match error via fail to integrate well with at least one of MonadPlus or MonadError.
I respectfully disagree. It is far too easy to use fail in a stack of monad transformers and end up using the wrong instance and getting error "message" semantics; it is far safer to use the appropriate MonadPlus function. fail is a disaster, from both an engineering and theoretical standpoint, and I cannot in good conscious recommend that people use it.
We don't disagree on the current state (my "I would still expect" should be read as "I would like to see", not as "I assume";-). But fixing that state would be another proposal, and one that would need careful design work. Currently, fail is the only program hook into pattern-match failure (for instance, when writing a library for first-class patterns that allows to lift plain Haskell patterns into first-class patterns, or when embedding rewrite rules in Haskell while simply reusing Haskell patterns). So I would prefer not to make the situation any worse by replacing a useable fail with error, as proposed in this thread. Claus

On June 29, 2010 18:32:51 Edward Kmett wrote:
'Either' takes on the connotation of being the 'sum type' for the category of Haskell types. This sum type has a very well formed and simple monad, that has a lot of useful theoretical properties, and is useful in a strictly larger array of scenarios than the monad with the error constraint, with the one notable exception that it doesn't handle the 'fail' property that was bolted into Monad in Haskell 98.
On the topic of 'fail' being an abomination, is there any hope of fixing this? Perhaps it could be pushed it into it's own type class, which would then required by the do notation? Exactly like mdo required MonadFix. I understand there was one called MonadZero for this at some time? I could see one route would be to add a compiler flag that would switch the do notation requirement from Monad to MonadZero. Instances could then be added to code until at some point it could become the default. A bit longer after that, it could be dropped altogether along with fail in the Monad class. Cheers! -Tyson

On Wed, 30 Jun 2010, Tyson Whitehead wrote:
Perhaps it could be pushed it into it's own type class, which would then required by the do notation? Exactly like mdo required MonadFix. I understand there was one called MonadZero for this at some time?
I assume that there is no need to change the compiler, just the library, or even just the imports, since GHC will simply insert 'fail' where necessary and this automatically introduces the type class constraints that 'fail' has. If a custom 'fail' from a new MonadError class is in scope, then MonadError will be required for the whole expression that a 'do' block represents.

On 30/06/2010 16:44, Henning Thielemann wrote:
On Wed, 30 Jun 2010, Tyson Whitehead wrote:
Perhaps it could be pushed it into it's own type class, which would then required by the do notation? Exactly like mdo required MonadFix. I understand there was one called MonadZero for this at some time?
I assume that there is no need to change the compiler, just the library, or even just the imports, since GHC will simply insert 'fail' where necessary and this automatically introduces the type class constraints that 'fail' has. If a custom 'fail' from a new MonadError class is in scope, then MonadError will be required for the whole expression that a 'do' block represents.
I believe the reason that fail was moved into the Monad class was that having constraints pop up unpredictably just because you added a pattern match was ugly and inconvenient (rather like the rationale for dropping the Data constraint on seq, and the similar problem with implicit parameters). If you add another constructor to a single-constructor data type, do all your pattern matches suddenly generate new constraints, requiring you to fix all your type signatures? I don't know all the ins and outs of the discussion here, but before proposing to reverse this decision someone should do a careful assessment of the prior rationale and results of subsequent experience. Cheers, Simon

On Thu, Jul 01, 2010 at 11:35:24AM +0100, Simon Marlow wrote:
I don't know all the ins and outs of the discussion here, but before proposing to reverse this decision someone should do a careful assessment of the prior rationale and results of subsequent experience.
The general question of fail is a side issue -- the question here is just whether the Monad instance for Either should define fail, and if so to what.

On Wed, Jun 30, 2010 at 10:25 AM, Tyson Whitehead
On June 29, 2010 18:32:51 Edward Kmett wrote:
'Either' takes on the connotation of being the 'sum type' for the category of Haskell types. This sum type has a very well formed and simple monad, that has a lot of useful theoretical properties, and is useful in a strictly larger array of scenarios than the monad with the error constraint, with the one notable exception that it doesn't handle the 'fail' property that was bolted into Monad in Haskell 98.
On the topic of 'fail' being an abomination, is there any hope of fixing this?
There was a hotly debated discussion about this during Haskell 98. What happened was we lost the notion of 'failure free' patterns, and the commitee at the time opted in favor of making it so that changing a pattern wouldn't cause your type signature to change. In retrospect, this was probably a bad idea. The cases where you want to pattern match on the left hand side, you probably do want to know that your operation can fail. Universally quantifying over Monad would then give you a guarantee that you don't fail just due to desugaring, but then universal quantification wasn't a tool in the toolchest at the time. Erik Meijer fought the good fight trying to preserve the semantic purity of "Monad", but ultimately was crushed under the press of bodies on the other side of the debate. I think this is one of those cases where Einstein's "Everything should be made as simple as possible, but no simpler" rule was violated through excess simplification. ;) http://www.cse.unsw.edu.au/~dons/haskell-1990-2000/msg03267.html As with all bad things Monad, like the lack of Functor as a superclass, the current situation is a result of a pile of perhaps pretty-bad-in-retrospect decisions made at the time. (In the case of Functor it was seen as an extra burden on the Monad implementor, but in practice, everyone who builds a Monad builds it anyways, and with transformers, you don't 'roll your own' nearly as often as you used to.) I'd welcome the re-opening of both issues: fail and instance Functor m => Monad m, but those discussions are better reserved for Haskell 201x, since changing it impacts support for Haskell 98. -Edward Kmett
Perhaps it could be pushed it into it's own type class, which would then required by the do notation? Exactly like mdo required MonadFix. I understand there was one called MonadZero for this at some time?
I could see one route would be to add a compiler flag that would switch the do notation requirement from Monad to MonadZero. Instances could then be added to code until at some point it could become the default. A bit longer after that, it could be dropped altogether along with fail in the Monad class.
Cheers! -Tyson

On Wed, Jun 30, 2010 at 5:05 PM, Edward Kmett
I'd welcome the re-opening of both issues: fail and instance Functor m => Monad m, but those discussions are better reserved for Haskell 201x, since changing it impacts support for Haskell 98.
Backwards compatibility aside, these proposals will certainly be very welcome. Some day we'll all have to bite the bullet anyway. Cheers! -- Felipe.

Edward Kmett wrote:
A reasonable case can be made for the existence of a monad that does something useful with fail. I don't think that that monad should be Either.
'Either' takes on the connotation of being the 'sum type' for the category of Haskell types. This sum type has a very well formed and simple monad, that has a lot of useful theoretical properties, and is useful in a strictly larger array of scenarios than the monad with the error constraint, with the one notable exception that it doesn't handle the 'fail' property that was bolted into Monad in Haskell 98.
Indeed. For type-level programming and category theoretic tricks, it is essential to have some canonical type for representing primitive type sums, with no additional semantic baggage. Either is the most obvious candidate for that role, and is frequently used for it as well. That it had been coopted for other purposes not related to being a primitive sum is an unfortunate historical problem.
The obvious name for such a monad would be Error, to go with ErrorT, but the Error class conflicts with that name, but perhaps:
data Fail e a = Error e | OK a
would be worth adding to Control.Monad.Error, during the same general timetable as this change, to provide users who really want the existing mtl Either semantics an upgrade path.
+1. It would be nice to distinguish the sums-as-errors type from the primitive-sum type.
In the interest of not killing this proposal with bikeshedding concerns over what to call it (Fail, Err, Error, etc), we should probably put that forward as a completely separate libraries proposal though.
+1 for dodging bikesheds. -- Live well, ~wren

On Wed, Jun 30, 2010 at 12:13:07AM +0200, Claus Reinke wrote:
The proposal is to move the Monad and MonadFix instances for Either (currently in the mtl package) to Control.Monad.Instances and Control.Monad.Fix respectively (both in the base package). The Monad instance is still an orphan, to retain Haskell 98 compatibility, but the MonadFix instance is together with its class. The Error constraint is removed from both instances, and the default definition of fail is used.
-1, because the default definition of fail is error, which would render the Monad instance useless (unless I'm missing something?).
You would just use Left instead of 'fail' if you want to show failure in an Either value.
a) you are suggesting to bypass a method of the proposed Monad instance because it isn't useful, I am suggesting not to define a Monad instance with unusable methods b) desugaring of pattern-match failure in Monads calls fail, not Left
However, there is no particular reason to associate 'Left' with failure. Not having fail be 'Left' is a signifigant feature, not a limitation of an Either instance. A notable example would be a constraint solver, an algorithm might attempt various solution strategies, even recursively calling itself on subproblems and return the first solution found via 'Left', happily jumping out of the whole computation with its prize. Strangely enough, this means 'Left' indicates success and 'Right' indicates failure in some sense. Defining 'fail' to be Left anything is clearly not correct. 'Either' is a monad with a non-local return, _not_ necessarily an error monad. The fact we can't come up with a sensible 'fail' for it is not an indication of a problem with fail, or with either, but with simply assuming incorrectly that a non-local return must mean failure, we should have accepted what the type system was telling us and realized that we shouldnt be giving it a fail :). I do think we should make a dedicated failure monad though. It is also a useful thing. John -- John Meacham - ⑆repetae.net⑆john⑈ - http://notanumber.net/

-1, because the default definition of fail is error, which would render the Monad instance useless (unless I'm missing something?). However, there is no particular reason to associate 'Left' with failure. Not having fail be 'Left' is a signifigant feature, not a limitation of an Either instance. .. this means 'Left' indicates success and 'Right' indicates failure in some sense. Defining 'fail' to be Left anything is clearly not correct.
While I do not find the particular example convincing, I agree that there is a tension about wanting to use both injections of the sum type vs leaving one for other uses. It is not a question of constructor names, it is partly to do with Haskell constructor classes forcing us to use the last type parameter as the return parameter and partly with Either having just enough injections to accomodate one extra piece of information. Anyway, since I want to use Left for fail messages (at least sometimes) and you want to use Left for something else (at least hypothetically), it does not seem to be a good idea to fix one Monad instance in base that is sure to disappoint one of us, right? Once people start importing Control.Monad.Instances in their packages, as they will when mtl and co start depending on that, one of us is stuck with an Either Monad they cannot use.
'Either' is a monad with a non-local return, _not_ necessarily an error monad.
Either is just a sum type. There are classes that want to use it for non-local returns (MonadError) and classes that want to use it for sums (MonadPlus). And if I believe you, there are uses that want to use it for something else, or at least the other way round (btw, while it doesn't really matter whether we drive on the Right or on the Left, it does matter that we all agree on one convention:-). The problems start when all of these classes are linked to a single Monad instance, and the 'fail' that has been put in it. So far, I had thought that there was a way to have all common uses of Either compatible with a single 'fail' (representing both non-local returns and empty sums), so I've been arguing to keep a sufficiently general Monad instance for Either. If you are certain that is not possible, none of the mutually incompatible Monad instances should go in base (mtl should simply use its own Either variant)!
The fact we can't come up with a sensible 'fail' for it is not an indication of a problem with fail, or with either, but with simply assuming incorrectly that a non-local return must mean failure, we should have accepted what the type system was telling us and realized that we shouldnt be giving it a fail :).
I do think we should make a dedicated failure monad though. It is also a useful thing.
As long as we have MonadPlus and MonadError instances for Either, I assume that we've already decided to use Either for both sums and failure. I'm not saying that could not be changed, but if someone wants to use Either in ways that are not compatible with these existing uses, why should everyone else have to adapt? Claus

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 7/1/10 04:27 , Claus Reinke wrote:
The problems start when all of these classes are linked to a single Monad instance, and the 'fail' that has been put in it. So far, I had thought that there was a way to have all common uses of Either compatible with a single 'fail' (representing both non-local returns and empty sums), so I've been arguing to keep a sufficiently general Monad
(a) I would guess not. (b) It strikes me that trying to make one Either do both of these is just wring. Either is a perfectly reasonable sum type; "fail" is not a general attribute of sum types, though. IMO "fail" should be associated with a MonadFailure (which might conceivably be a typeclass which has Either as an implementation; but given the lack of useful information available in its most common usage as part of the "do" machinery, Maybe is just as reasonable an implementation). That said, I'm also not sure if fail maps to the perennially-suggested MonadZero entirely sensibly, btw. Okay, obviously it's related to mzero in some conceptual sense, but it seems to me that it's not related to monoids; instead, it's an exception. The fact that fail is usually implemented as a call to error is symptomatic of this; and treating an exception as a monoid strikes me as a failed abstraction. (On the gripping hand, a MonadFailure typeclass would give people who wanted it the option of doing so. Of course, if you do this then it simply replaces the current question with the question of whether the Either monad should have a MonadFailure instance that is an exception or simply Left, and what happens if someone disagrees... there are no easy answers.) - -- brandon s. allbery [linux,solaris,freebsd,perl] allbery@kf8nh.com system administrator [openafs,heimdal,too many hats] allbery@ece.cmu.edu electrical and computer engineering, carnegie mellon university KF8NH -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.10 (Darwin) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkwsVkQACgkQIn7hlCsL25VF/QCbBrU+NFx9bEzQva0awdLwZgV5 zyYAoIwemwZUBbLSWEnextXSvjiYR0xG =egxO -----END PGP SIGNATURE-----

On Thu, Jul 01, 2010 at 10:27:39AM +0200, Claus Reinke wrote:
Anyway, since I want to use Left for fail messages (at least sometimes) and you want to use Left for something else (at least hypothetically), it does not seem to be a good idea to fix one Monad instance in base that is sure to disappoint one of us, right? Once people start importing Control.Monad.Instances in their packages, as they will when mtl and co start depending on that, one of us is stuck with an Either Monad they cannot use.
It will happen long before that: Control.Monad.Instances is imported directly by Control.Applicative and Control.Monad.Fix, and hence by Control.Arrow, Data.Foldable, Data.Traversable, the ST modules and the modules in containers. Anyone straying outside of haskell98 will probably get it. With Haskell as it is, local instances are unworkable. We do have to decide on a single instance (unless no instances at all are possible).
[John Meacham wrote:]
'Either' is a monad with a non-local return, _not_ necessarily an error monad.
Either is just a sum type. There are classes that want to use it for non-local returns (MonadError) and classes that want to use it for sums (MonadPlus). And if I believe you, there are uses that want to use it for something else, or at least the other way round
No, he also wants to use Left for non-local returns, but argues that such returns are not always failures. It seems to me that MonadPlus is not a good fit for Either -- how can it be a monoid?

Ross Paterson wrote:
The proposal is to move the Monad and MonadFix instances for Either (currently in the mtl package) to Control.Monad.Instances and Control.Monad.Fix respectively (both in the base package). The Monad instance is still an orphan, to retain Haskell 98 compatibility, but the MonadFix instance is together with its class. The Error constraint is removed from both instances, and the default definition of fail is used.
+1 Yay! Claus Reinke wrote:
-1, because the default definition of fail is error, which would render the Monad instance useless (unless I'm missing something?).
It would certainly not render it useless. When using Either as an error monad, the usual way to throw an error is with throwError if you are using the MonadError class, or with Left if not. At least on the surface, "fail" has nothing to do with the concept of failure that Control.Monad.Error is modeling. Instead, it is referring to "failure of a pattern match in the do-block variable binding syntax" (and its extension to list comprehensions). In my opinion, relying on a failed pattern match to result in a Left value when using the Either monad for error processing is poor programming technique. As is using the "pattern match failure" function directly in place of throwError or Left. There are plenty of better and safer ways to achieve polymorphism. However, some may disagree, so that would be a downside to this proposal. Even so, I am still strongly in favor, for the reasons well-explained by Edward. Another downside is that there may be some code out there that does use the "pattern match failure" function in this way (erroneously in my opinion). I am still strongly in favor. However, it would be a good idea to search Hackage to get an idea of the scope of the breakage ahead of time, so that we can prepare for it. Regards, Yitz

-1, because the default definition of fail is error, which would render the Monad instance useless (unless I'm missing something?).
It would certainly not render it useless.
True. That was an overstatement, based on some particular use cases I happen to care about, and which this proposal would break. But consider 'Either a' as a refinement of Maybe: the proposed new 'Monad (Either a)' instance is not only less defined that the current instance, it is less defined than the existing 'Monad Maybe' instance. Either having more structure to represent information but its Monad instance capturing less information than Maybe makes no sense to me.
When using Either as an error monad, the usual way to throw an error is with throwError if you are using the MonadError class, or with Left if not.
At least on the surface, "fail" has nothing to do with the concept of failure that Control.Monad.Error is modeling.
I am not talking about Control.Monad.Error failure, I am talking about things that can happen in a monadic computation, and increasingly refined data types that allow us to capture more and more of that (Id, Maybe, Either a, [], as in the old Monad papers). Whether we then structure the processing of the captured information according to MonadError or MonadPlus or something else, is a different story. However, it is my experience that the most useful definitions of fail for my purposes were those that corresponded to mzero.
Instead, it is referring to "failure of a pattern match in the do-block variable binding syntax" [..] In my opinion, relying on a failed pattern match to result in a Left value when using the Either monad for error processing is poor programming technique.
Why? Unless you choose to throw away the information (resorting to exceptions where simple data structure suffices), Left is the obvious candidate (since Right is taken for return).
As is using the "pattern match failure" function directly in place of throwError or Left.
How do you want to capture pattern match failure in an 'Either a' Monad if fail is defined as error?
However, it would be a good idea to search Hackage to get an idea of the scope of the breakage ahead of time, so that we can prepare for it.
Moving a 'Monad (Either a)' instance is going to break things outside hackage, too (I think I first encountered this issue when combining Strafunski and Programatica for use in HaRe). It is also going to unbreak some things (where two packages defined equivalent instances), which is the point of the proposal, but will cause version bumps and incompatibilities. So this is going to be a breaking change, not something one would want to get wrong or have to redo. Hackage stats would be useful, also a "heads up" warning on haskell-cafe. The only way to fix rather than move the orphan instance issue here would be for mtl and the like to use their own Either-variants. Instead, this proposal appears to be about fixing a single 'Monad (Either a)' instance in base. Which might be good, but that instance should better be right for everyone. Claus

On Wed, Jun 30, 2010 at 4:24 PM, Claus Reinke
True. That was an overstatement, based on some particular use cases I happen to care about, and which this proposal would break. But consider 'Either a' as a refinement of Maybe: the proposed new 'Monad (Either a)' instance is not only less defined that the current instance, it is less defined than the existing 'Monad Maybe' instance. Either having more structure to represent information but its Monad instance capturing less information than Maybe makes no sense to me.
But you know more about Maybe, than you do about 'Either a' namely that there is no information in its Nothing/Left alternative. So given just Either a and Maybe, neither subsume the other. You know you can construct an element in the limit of Maybe: Nothing, but you don't know that such an object exists forall a. in Either a. You can make the same statement about particular choices of a. i.e. that Either () might a well be Maybe except for an extra bottom, but the instance head, being Haskell 98 has to be formed "Monad (Either a)" which means that you have to constrain (as mtl does) all Eithers to support such an empty value, or constrain none of them. The version that Ross puts forward is the version that can make sense inside of Base. It fits with the module it is moving into, it doesn't require Base adopting whole-hog the Control.Monad.Error.Class machinery, and it drops a value that is an instance for a prelude type into the class where it belongs. With that change, the mtl is no longer defining instances for any types it doesn't own! Both of these changes feel right from an implementation perspective, even if they come at the cost of a switch to folks leaning on the existing mtl semantics. Already people using the mtl will need to ready themselves for a much similar set of changes involving the constructor names used by all of of State/Reader/Writer etc switching to type aliases around their transformer versions, as mtl becomes an alias for monads-fd + transformers. In that vein it makes sense that the basic error type used by transformer-centric should ALSO be a type alias wrapped around ErrorT, rather than an abuse of a prelude type. -Edward Kmett

Sorry for being inarticulate in haste, a couple of typo corrections: The version that Ross puts forward is the version that can make sense inside
of Base. It fits with the module it is moving into, it doesn't require Base adopting whole-hog the Control.Monad.Error.Class machinery, and it drops [an instance] for a [prelude type] into the [module] where it belongs.
In that vein it makes sense that the basic error type used by
transformer-centric [code] should ALSO be a type alias wrapped around ErrorT, rather than an abuse of a prelude type.
-Edward Kmett

On Wed, Jun 30, 2010 at 05:46:27PM -0400, Edward Kmett wrote:
With that change, the mtl is no longer defining instances for any types it doesn't own!
Not quite -- there are still two orphans: instance MonadPlus IO instance (Error e) => MonadPlus (Either e)
In that vein it makes sense that the basic error type used by transformer-centric should ALSO be a type alias wrapped around ErrorT, rather than an abuse of a prelude type.
Indeed, and the ideal name for the type alias would be ...? I'm starting to think it would be best for transformers to start over on this monad, say with a new unconstrained ExceptT/Except, beside ErrorT.

On Tue, Jun 29, 2010 at 09:16:03PM +0200, Claus Reinke wrote:
-1, because the default definition of fail is error, which would render the Monad instance useless (unless I'm missing something?).
I don't see this as a problem, the either monad provides a generic monad with a short-circuit return, there is no particular reason to associate a short circuit return with failure. There can be many reasons you want a short circuit return rather than just a concept of 'failure'. The original mistake was thinking that 'Left' had to be associated with failure or errors for some reason. Like any other monad without a sensible definition for 'fail', the default of 'error' is just fine. John -- John Meacham - ⑆repetae.net⑆john⑈ - http://notanumber.net/

Ross Paterson wrote:
The proposal is to move the Monad and MonadFix instances for Either (currently in the mtl package) to Control.Monad.Instances and Control.Monad.Fix respectively (both in the base package). The Monad instance is still an orphan, to retain Haskell 98 compatibility, but the MonadFix instance is together with its class. The Error constraint is removed from both instances, and the default definition of fail is used.
+1 btw. -- Live well, ~wren
participants (16)
-
Bas van Dijk
-
Brandon S Allbery KF8NH
-
Cale Gibbard
-
Claus Reinke
-
David Waern
-
Edward Kmett
-
Edward Z. Yang
-
Evan Laforge
-
Felipe Lessa
-
Henning Thielemann
-
John Meacham
-
Ross Paterson
-
Simon Marlow
-
Tyson Whitehead
-
wren ng thornton
-
Yitzchak Gale