Is_positive, etc


#1

Easy question: As far as I can tell, there are no functions that test for a float or int being positive, negative, nonnegative, etc. the standard library, Batteries, or Jane Street Core. It’s simple to define one’s own, e.g.:

let is_positive = ((<) 0.)

but I just wanted to check whether it’s correct that this kind of function isn’t already available.

More interesting question (maybe): > is polymorphic (is that the right term?) since it works with both ints and floats. Would it be possible to define a polymorphic is_positive function? I don’t know how to do it (I had to choose 0 or 0. above), and I think the answer is no, but since > is polymorphic, why not something defined in terms of it?


#2

Uhm, why should there be? It is really quite trivial.

Yes, that is the right term. When you look at the signature of (<) you’ll notice it is 'a -> 'a -> bool. When you now pass in a value like 0. the first 'a will be float, but since all 'a must be the same type, the other 'a is now float too, thus your function will have a signature of float -> bool. Since there are no polymorphic numerals with a type 'a (like a “zeroish” value), that’s the best you can do.


#3

Thanks very much, @Leonidas.

There’s no overwhelming reason to have predefined is_positive etc. function, and your response is a good reason against having them predefined. It’s fine with me either way . Small reasons in favor of predefining these tests include:

  • For me, at least, is_positive is clearer than ((<) 0.) or (fun x -> x > 0.). Others may feel similarly.
  • From what I have read, ((<) 0.), although nice and short, could be less efficient in an inner loop because it uses partial application, so a longer definition might be better.
  • Many people will define is_positive over and over, and over, and … again, wasting time and space.
  • There are at least eight different handy predicates, for positive, nonnegative, negative, and nonpositive, applied to both ints and floats. So one might need at least eight lines of code (over and over … again).
  • If you want both int and float tests, then you either have to name them things like float_is_positive or else define your own modules for the int and float versions (with potential module name clashes with other modules).
  • Some people will use different names–is_pos, pos, postiive, is_positive, float_is_positive, Float.is_positive, is_posf, etc.–potentially hindering understanding of a set of very common, basic tests.
  • There are special contexts in which analogous functions are not so trivial. For example, Owl defines is_positive, etc. for matrices (true if and only if all elements are positive). Defining common int and float operators in a central (“core” was already taken) library sets a standard; other writers of less central libraries can then choose to use the same function names, if they want, in order to help users of the new library.

Every one of these is a very minor consideration, however.

It might be that something like ((<) 0.) has become a common idiom, so that experienced OCaml users can read it very quickly. (I look at it and have to think for a moment, mentally adding in the missing argument and moving the “<” between the 0. and the argument. I don’t mind reading partial application in general, though, and I’m used to prefix syntax for mathematical operators from lisps, so maybe I’m just confusing myself for no reason. If there is a common idiom, I should just get used to it.)

I guess that the special polymorphism of the comparison operators is a bit mysterious to me, given that ints and floats are distinguished for all (?) other mathematical functions. I suspect that further clarification would require a rather lengthy discussion. There is probably something that I can read elsewhere about the difference between comparison operators and arithmetic operators in this regard.


#4

As a side note, I would like to kindly point out that ((<) 0.) literally reads “less than zero”, which would be a wrong interpretation.

When I have to extract the positive elements from a list, I prefer to use List.filter (fun x -> x > 0.) or List.filter is_positive rather than List.filter ((<) 0.).


#5

Comparison in in a similar way “magical” as the compare function is, which seemingly works on all 'a. I believe the consensus has been “it was not a great idea, but here we are now”. I concur that this might yield a lengthy discussion, mostly centered about how its been done historically. Not sure it’s worth delving into, really.


#6

That’s helpful to know, actually. (If it’s a historical artifact, the difference between > and + is no longer puzzling. It’s just what happens all the time, and OCaml has very little of this kind of thing.)

I hadn’t really thought about compare. Thanks.


#7

Check this.