5

I have derived a statement (theorem?) that puzzles me. I wonder if my logic is sound.

Any commutative non-strict function f :: a -> a -> b is a constant.

Commutativity is understood including the bottoms, i.e. f x y and f y x either both terminate, or both don't.

My informal reasoning is as follows. Suppose f is a non-strict function. Then there exists a such that either f a ⊥ or f ⊥ a terminate. If f is commutative, then both should terminate. But then f cannot scrutinise either of its arguments. (If it scrutinises the first argument first, then f ⊥ a must be , and vice versa). So it must be a constant function.

Is this reasoning correct?

It clearly fails if f is allowed to scrutinise both arguments at the same time and succeed if either one is not a . But are such functions allowed in (some reasonably conservative extension of) Haskell?

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • 4
    in other words, a commutative function (with bottoms) is either strict in both arguments (like e.g. `+`), or in none (which must be constant then). seems right, for if it's strict in one but not the other then one of the flipped calls will fail and the other succeed when one of the arguments is bottom. seems right to me FWIW. – Will Ness Aug 04 '20 at 16:42
  • 4
    http://hackage.haskell.org/package/unamb-0.2.7/docs/Data-Unamb.html#v:parCommute – leftaroundabout Aug 04 '20 at 18:12
  • Are you using "non-strict" in some formal way? I can imagine a function which scrutinises its arguments partially, (i.e. something like min on the natural numbers), so it can produce an answer for some inputs which contain bottom (min 3 inf), but that statement "Then there exists a such that either f a ⊥ or f ⊥ a terminate." seems not to hold – oisdk Aug 04 '20 at 18:15
  • @leftaroundabout Hmm this is using unsafePerformIO and friends to start threads... kinda cheating, but maybe not. Thanks for the pointer. – n. m. could be an AI Aug 04 '20 at 18:39
  • @oisdk a non-strict function is one that terminates having at least one non-terminating argument. there may be both more or less nuanced definitions, see https://wiki.haskell.org/Non-strict_semantics . `min` is strict. – n. m. could be an AI Aug 04 '20 at 18:47
  • 2
    Are you making this claim about any function `f` which can be given the type `forall a b. a -> a -> b`, or are you making this claim about any function `f` which can be given a type that unifies with `forall a b. a -> a -> b`? That is, if I could find a counterexample `f` of type `Bool -> Bool -> Bool`, say, would that be an interesting outcome for the purposes of this question or not? (In particular, you appear to lean on parametricity for the claim that if both `f a _|_` and `f _|_ a` terminate, then `f` cannot scrutinise either of its arguments.) – Daniel Wagner Aug 04 '20 at 20:28
  • 3
    One could argue that `f :: Int -> Int -> [Int] ; f x y = [x+y]` is commutative, non strict, non constant. This relies on `[ _|_ ]` being distinct from `_|_`. If you for some reason consider this to be strict, you should more precisely define your strictness notion. – chi Aug 04 '20 at 21:41
  • @DanielWagner the second one – n. m. could be an AI Aug 05 '20 at 06:23

1 Answers1

2

chi writes

One could argue that

f :: Int -> Int -> [Int]
f x y = [x+y]

is commutative, non-strict, and non-constant. This relies on [ _|_ ] being distinct from _|_. If you for some reason consider this to be strict, you should more precisely define your strictness notion.

Indeed, this is the case! Given any non-constant, commutative function f, you can write a non-strict, non-constant, commutative function by wrapping an application of f in one or more lazy constructors.

dfeuer
  • 48,079
  • 5
  • 63
  • 167