3

I recently tried running the code:

> let _l_ = _l_
> any [True, _l_, False]
True
> any [False, _l_, True]

> -- _l_

I was wondering if this is considered correct behavior since any is defined as foldr (||) False and || is associative and commutative.

Shouldn't _l_ || True == True || _l_ be true, and (False || _l_) || True == False || (_l_ || True) be true?

How would I implement an any that would result in an associative, commutative function application?

I am new to trying to understand bottom; should || be returning at all?

Thanks

user2063685
  • 159
  • 6
  • 1
    Well, once the value computed by the `foldr` has at some point in the list become `True`, the definition of `||` shows that in `True || x`, the `x` does not need to be evaluated – the result is always `True`. So if the `foldr` has so far seen a `True`, the rest of the list is unevaluated thanks to laziness. In the second case, the bottom is seen at a point where no `True` has yet been encountered, so that bottom *does* have to be evaluated. Evaluating bottom yields bottom. With bottom, `||` isn't really commutative: `True || undefined` is `True`, while `undefined || True` is `undefined`. – gspr Dec 06 '13 at 08:10
  • 1
    You are mixing commutativity and laziness. _If_ `||` were not lazy, it would produce `True || _l_ == _l_ || True` – Sassa NF Dec 06 '13 at 08:32
  • `||` is not commutative if you consider bottom. – augustss Dec 06 '13 at 14:47

2 Answers2

2

This behavior is correct.

Shouldn't _l_ || True == True || _l_ be true

This isn't true in the presence of bottom. || has to evaluate one side first, then iff that value is False, it has to evaluate the other side. The definition from GHC.Classes is

(||)                    :: Bool -> Bool -> Bool
True  || _              =  True
False || x              =  x

So you can see it checks the left argument first. If the left argument is bottom, then the computation diverges and the whole thing is bottom. But if the left argument is True, the right argument is never examined, so even if it's bottom the result is still True.

(False || _l_) || True == False || (_l_ || True) be true?

This is true, both values are bottom. || is associative even in the presence of bottoms, but not commutative.

There are a few approaches you can take to building a commutative any, but they tend to involve concurrency. One approach is to use a function like por, which races two values and returns True if either is True, False if both return False, and otherwise diverges. Or you could build it yourself.

John L
  • 27,937
  • 4
  • 73
  • 88
  • (repeat False) ++ [True] won't evaluate to True. so even `por` is not commutative. I don't think anyone can offer commutativity in the presence of non-termination. – Sassa NF Dec 06 '13 at 09:10
  • @SassaNF: You can make it strict in both arguments and that will make it commutative; however, you will lose short-circuiting that way. – Vitus Dec 06 '13 at 14:47
  • @SassaNF Is it a mathematical property of bottom that prevents commutativity, or is it because it is not possible to implement in the real world? – user2063685 Dec 06 '13 at 17:04
  • @user2063685, @Vitus and others (even me) mentioned that if `||` were strict, it would become commutative again - but this is to be understood in some very loose sense. Mathematically `_|_` is a uninhabited type, meaning that it does not have any way to construct a value, and consequently no way to define equality. So it is not possible to demonstrate that `_|_ || True` and `True || _|_` _are_ in fact equal, even if we declare `||` strict. – Sassa NF Dec 06 '13 at 21:41
  • @SassaNF: `⊥` does not mean the empty type in this context. It means non-termination or error (`undefined`, `error`). In Haskell, we do not have truly empty type, precisely because `⊥` (think `undefined`) can be given any type. If we think of `Bool` as `Bool = {True, False, ⊥}`, then strict `||` is indeed commutative. – Vitus Dec 07 '13 at 18:29
  • @Vitus I don't think your interpretation is correct. To start with, `undefined` and `error` are not ⊥, here we witness Exception monad. I don't argue about loose meaning of commutativity, but since the question was about strict mathematic meaning, I propose you formulate a way to compare the two bottoms. For example, comparing True and False is easy - they are two different constructors, equality is defined. I don't see how you can do that for whatever you think the bottom is here, but will be glad to be corrected. – Sassa NF Dec 07 '13 at 22:37
  • @SassaNF: I'm basing this mostly on [Haskell wikibook section about denotational semantics](http://en.wikibooks.org/wiki/Haskell/Denotational_semantics); but as far as I know, it's quite common to treat all bottoms as being equal, since you can't distinguish them from inside the program (well, the pure part at least, once you are in `IO`, you can for example distinguish exceptions). So yes, from this point of view, strict `||` is indeed commutative. If you go with `IO`, all bets are off, though. – Vitus Dec 07 '13 at 23:39
0

I think commutativity can be promised only on "classical logic" segment. Once you permit "non-classical" results, like non-termination, it is not possible to guarantee what the outcome is going to be, let alone commutativity.

For example, evaluating any (repeat False++[True]) is never going to produce the same result as any (True:repeat False).

augustss
  • 22,884
  • 5
  • 56
  • 93
Sassa NF
  • 5,306
  • 15
  • 22
  • Those two expressions are not equal. You must have some commutative version of `:` in mind. – augustss Dec 06 '13 at 14:51
  • @augustss In the context of topic starter applying `any` to a list of values, it is just another way of supplying bottom as one of the arguments to `||`. – Sassa NF Dec 06 '13 at 15:42
  • @SassaNF: I agree that this illustrates some of the difficulties of working with non-terminating computations, but this is a different case from that of the question. The operator you use to combine `repeat False++[True]` is entirely irrelevant here, as your fold requires an infinite traversal to ever reach a `True` element. – John L Dec 09 '13 at 00:03