I am currently learning F# on my own (via the try f# site). I have the following (imho) tail-recursive function for existential quantification of a unary predicate (int->bool).
let rec exists bound predicate =
if (bound<0) then false
elif predicate(bound) then true
else exists (bound-1) predicate
Now this function can also be written as
let rec exists bound predicate = (bound+1>0) && (predicate(bound) || exists (bound-1) predicate)
However, the second implementation is not tail-recursive. The question is whether or not the compiler will optimize it to tail-recursive?
How is the situation for even simpler (ok, it is a bit silly) examples, say
let rec hasNoRoot f =
if (f x = 0) then false
else hasNoRoot (fun x -> f (x+1))
versus
let rec hasNoRoot f = (f 0 <> 0) && (hasNoRoot (fun x-> f(x+1)))
in the second example, in order to recognize the function (its description actually) as tail-recursive, the compiler only needs to "know" that in order to evaluate a conjunction, not necessarily both conjuncts have to be evaluated.
thanks for any advice