
monad-bool implements a pair of Boolean monoids and monads, to support short-circuiting, value-returning computations similar to what Python and Ruby offer with their native && and || operators. For example, in Python you might see this: x = [1,2,3,0] print x[1] || x[3] -- prints "2" With this library, you can now mirror such code in Haskell: let x = [1,2,3,0] print $ (x !! 1) ||? (x !! 3) -- prints "Success 2" "Booleanness" is based on each type having an instance of the 'Control.Conditional.ToBool' type, for which only the basic types are covered (Bool, Int, Integer, Maybe a, Either a b, [a], Attempt a). If you wish to define a truth value for your own types, simply provide an instance for ToBool: instance ToBool MyType where toBool = ... The And/Or monoids use the Attempt library so that the actual type of the successful results depends on case analysis. It could be a list, a Maybe, an Either, or an exception in the IO Monad. The monad variants, AndM, AndMT, OrM and OrMT provide short-circuiting behavior in a Monad, which returns the last value returned before truth was determined. Here are two examples: Use 'onlyIf' with AndM and AndMT to guard later statements, which are only evaluated if every preceding 'onlyIf' evaluates to True. For example: foo :: AndM Int foo = do onlyIf (True == True) return 100 onlyIf (True == True) return 150 onlyIf (True == False) return 200 When run with `evalAndM foo (-1)` (where (-1) provides a default value), 'foo' returns 150. Use 'endIf' with OrM and OrMT to chain statements, which are only executed if every preceding 'endIf' evaluated to False. For example: bar :: OrM Int bar = do endIf (True == False) return 100 endIf (True == False) return 150 endIf (True == True) return 200 When run with `evalOrM bar (-1)` (where (-1) again provides a default value), 'bar' returns 150. And please, somebody let me know if this has already been done. A search for likely candidates did not turn up anything obvious in Hoogle, but as my knowledge of the whole of Hackage is minimal, I would appreciate any wiser minds that can inform me. Thank you, -- John Wiegley FP Complete Haskell tools, training and consulting http://fpcomplete.com johnw on #haskell/irc.freenode.net

On Tue, 22 Jan 2013, John Wiegley wrote:
Use 'onlyIf' with AndM and AndMT to guard later statements, which are only evaluated if every preceding 'onlyIf' evaluates to True. For example:
foo :: AndM Int foo = do onlyIf (True == True) return 100 onlyIf (True == True) return 150 onlyIf (True == False) return 200
When run with `evalAndM foo (-1)` (where (-1) provides a default value), 'foo' returns 150.
Does the And monad fulfill the monad laws? In a proper monad an interim (return x) (without a '<-') is a no-op.

Henning Thielemann
writes:
Does the And monad fulfill the monad laws? In a proper monad an interim (return x) (without a '<-') is a no-op.
You are very right. I will make the necessary changes. -- John Wiegley FP Complete Haskell tools, training and consulting http://fpcomplete.com johnw on #haskell/irc.freenode.net

On 23 January 2013 08:04, John Wiegley
monad-bool implements a pair of Boolean monoids and monads, to support short-circuiting, value-returning computations similar to what Python and Ruby offer with their native && and || operators. ... Use 'onlyIf' with AndM and AndMT to guard later statements, which are only evaluated if every preceding 'onlyIf' evaluates to True. For example:
foo :: AndM Int foo = do onlyIf (True == True) return 100 onlyIf (True == True) return 150 onlyIf (True == False) return 200
When run with `evalAndM foo (-1)` (where (-1) provides a default value), 'foo' returns 150.
Use 'endIf' with OrM and OrMT to chain statements, which are only executed if every preceding 'endIf' evaluated to False. For example:
bar :: OrM Int bar = do endIf (True == False) return 100 endIf (True == False) return 150 endIf (True == True) return 200
John, these sound powerful, but how would I do something esoteric like if/elseIf/endIf ? Conrad.

Conrad Parker
writes:
these sound powerful, but how would I do something esoteric like if/elseIf/endIf ?
Can you show me an example of what you'd like to express? -- John Wiegley FP Complete Haskell tools, training and consulting http://fpcomplete.com johnw on #haskell/irc.freenode.net

On 23 January 2013 09:25, John Wiegley
Conrad Parker
writes: these sound powerful, but how would I do something esoteric like if/elseIf/endIf ?
Can you show me an example of what you'd like to express?
Your examples look vaguely like an if/elseif/else block from other languages, so I was wondering if mimicking that was possible. Also, can this be used with RebindableSyntax? http://www.haskell.org/ghc/docs/7.0.2/html/users_guide/syntax-extns.html#reb... Conrad.

* John Wiegley
monad-bool implements a pair of Boolean monoids and monads, to support short-circuiting, value-returning computations similar to what Python and Ruby offer with their native && and || operators.
Random thoughts after compiling/looking at the code: - your constraint on 'base' is too restrictive — I had to relax it in order to compile the package (my 'base' is 4.6.0.1, which came with GHC 7.6.2 RC) - personally I never missed "0 as False"... - what do you need unsafeCoerce for? Roman

Roman Cheplyaka
- what do you need unsafeCoerce for?
The unsafeCoerce is needed because the library is severely broken. Consider this: do onlyIf False x <- c onlyIf True return x There is a good reason why Haskell's type system would never have allowed to write this library. I recommend the author to try again without unsafeCoerce. It won't work. Also I'm quite sure that the monads don't have associative (>>) either. Consider this: yes = onlyIf True no = onlyIf False yes >> x >> no >> y According to the intended semantics this should result in 'x', but what does yes >> (x >> no) >> y result in? Greets, Ertugrul -- Not to be or to be and (not to be or to be and (not to be or to be and (not to be or to be and ... that is the list monad.

Ertugrul Söylemez
writes:
There is a good reason why Haskell's type system would never have allowed to write this library. I recommend the author to try again without unsafeCoerce. It won't work.
You are right, and in fact what I wanted to do cannot be done. It requires distinguishing the final value as either a Left (result from short-circuiting) or a Right (final value). And EitherT can already do that, it just lacks a convenience function to make it easier (i.e, not having to write lots of nested if statements). -- John Wiegley FP Complete Haskell tools, training and consulting http://fpcomplete.com johnw on #haskell/irc.freenode.net

John Wiegley
writes:
And EitherT can already do that, it just lacks a convenience function to make it easier (i.e, not having to write lots of nested if statements).
Never mind, when/unless + left work just fine for this. -- John Wiegley FP Complete Haskell tools, training and consulting http://fpcomplete.com johnw on #haskell/irc.freenode.net

John Wiegley
writes:
Never mind, when/unless + left work just fine for this.
You know, it's been a humorous day. First ekmett showed that I can't make a sane Monad instance for AndM or OrM. Then I discovered I can't make a reasonable Monoid (no mempty, given only 'toBool'), so I dropped down to a Semigroup. Further, my combinators for EitherT can be implemented using just 'when' and 'left' to provide the short-circuiting. Already I had very little code left, until he showed me the Applicative instance for Either, plus a little trick: >>> Right 1 *> Right 2 *> Left 2 *> Right 5 Left 2 -- same functionality as my And semigroup >>> let Left x |> y = y; x |> _ = x in Left 1 |> Right 2 |> Right 3 Right 2 -- same functionality as my Or semigroup And poof, all my code just disappeared... -- John Wiegley FP Complete Haskell tools, training and consulting http://fpcomplete.com johnw on #haskell/irc.freenode.net

If we step back, I think the lesson here is that Haskell libraries exist,
but the concepts are far enough from what you expect to exist given
background knowledge from another programming language.
So what is actually needed is not monad-bool, but the equivalent
documentation that makes a programmer which is not an expert in Haskell
connect the dots like you did today.
Alexander
On Wed, Jan 23, 2013 at 8:10 AM, John Wiegley
John Wiegley
writes: Never mind, when/unless + left work just fine for this.
You know, it's been a humorous day.
First ekmett showed that I can't make a sane Monad instance for AndM or OrM.
Then I discovered I can't make a reasonable Monoid (no mempty, given only 'toBool'), so I dropped down to a Semigroup. Further, my combinators for EitherT can be implemented using just 'when' and 'left' to provide the short-circuiting.
Already I had very little code left, until he showed me the Applicative instance for Either, plus a little trick:
>>> Right 1 *> Right 2 *> Left 2 *> Right 5 Left 2 -- same functionality as my And semigroup
>>> let Left x |> y = y; x |> _ = x in Left 1 |> Right 2 |> Right 3 Right 2 -- same functionality as my Or semigroup
And poof, all my code just disappeared...
-- John Wiegley FP Complete Haskell tools, training and consulting http://fpcomplete.com johnw on #haskell/irc.freenode.net
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

2013/1/23 John Wiegley
John Wiegley
writes: Never mind, when/unless + left work just fine for this.
You know, it's been a humorous day.
...
Don't take it so hard. Trying to reinvent something is always a great exercise and makes you really understand the problem. And it can have interesting results too. One of my university professors once heard about some concept, but didn't know the details. He tried to derive the concept himself, and he actually invented something different, new and very useful. ...
>>> let Left x |> y = y; x |> _ = x in Left 1 |> Right 2 |> Right 3 Right 2 -- same functionality as my Or semigroup
This strongly reminds me of `mplus` of `Maybe`. The problem is we cannot define a generic instance `MonadPlus Either` because we cannot define `mzero` (but if we restrict the left type, we can achieve this, like in "instance Error e => MonadPlus (Either e)"). Another possibility how to capture this "Or" behavior is `MonadError`. You could define |> for any instance of `MonadError`, including Either (currently with some restrictions): (|>) :: MonadError e m => m a -> m a -> m a x |> y = x `catchError` (const y) Best regards, Petr Pudlak

Petr P
writes:
Don't take it so hard. Trying to reinvent something is always a great exercise and makes you really understand the problem. And it can have interesting results too. One of my university professors once heard about some concept, but didn't know the details. He tried to derive the concept himself, and he actually invented something different, new and very useful.
Thank you very much to everyone for the encouragement, and especially to Edward and Shachaf for the education on #haskell. It will be hard to unlearn a lesson like this one. :) And I will certainly endeavor to make the most valuable mistakes I can from here on, with the help of such a gracious community. :) Yours, -- John Wiegley FP Complete Haskell tools, training and consulting http://fpcomplete.com johnw on #haskell/irc.freenode.net

Roman Cheplyaka
writes:
- what do you need unsafeCoerce for?
Ok, after much discussion with edwardk and shachaf, I came to realize a few things: 1. The functionality of my two monads 'AndM' and 'OrR' can be boiled down to two helper functions inside EitherT: returnIf :: Monad m => Bool -> e -> EitherT e m () returnIf p a = if p then left a else right () returnUnless :: Monad m => Bool -> e -> EitherT e m () returnUnless p = returnIf (not p) These let you short-circuit monadic computations, returning the short-circuiting value as a Left; or as a Right if it reaches the end. 2. The 'shortcircuit' library already provides short-circuiting variants of && and || that work just like Python's and Ruby's. In fact, I think I'll talk to aristid about merging my Monoid definitions into that library. Here are the updated docs: http://ftp.newartisans.com/pub/monoid-bool/Data-Monoid-Bool.html I'll ask Ross Paterson to deprecate monad-bool. And in future, I'll seek review here first before uploading. -- John Wiegley FP Complete Haskell tools, training and consulting http://fpcomplete.com johnw on #haskell/irc.freenode.net

Em 23/01/2013 04:03, "John Wiegley"
I'll ask Ross Paterson to deprecate monad-bool. And in future, I'll seek review here first before uploading.
Release early and release often, don't worry about asking the mailing list beforehand (unless you want to, of course). Cheers, -- Felipe.

On Wed, Jan 23, 2013 at 5:28 PM, Felipe Almeida Lessa < felipe.lessa@gmail.com> wrote:
don't worry about asking the mailing list beforehand (unless you want to, of course).
Seconded! Just a cursory sweep of this thread reveals so much learning and discovery taking place that would be utterly lost should a self-censoring arrant pedantry take hold. Props to John for motivating the use case (on haskell-cafe, no less!) for monad-bool that sparked this discussion in the first place. Half of the time, I can't tell what problem a package is trying to solve. I look forward to seeing more of his contributions. -- Kim-Ee
participants (9)
-
Alexander Kjeldaas
-
Conrad Parker
-
Ertugrul Söylemez
-
Felipe Almeida Lessa
-
Henning Thielemann
-
John Wiegley
-
Kim-Ee Yeoh
-
Petr P
-
Roman Cheplyaka