[m-users.] Ambiguous tail recursion?
Julian Fondren
jfondren at minimaltype.com
Wed Jul 17 12:42:28 AEST 2019
On 2019-07-16 21:14, Julien Fischer wrote:
> Hi,
>
> On Tue, 16 Jul 2019, Julian Fondren wrote:
>
>> Consider this module:
>>
>> :- module tailornot.
>> :- interface.
>> :- import_module io.
>> :- pred main(io::di, io::uo) is det.
>> :- implementation.
>> :- import_module list, bool, int.
>>
>> main(!IO) :-
>> X = (test([1, 2, 3]) -> yes; no),
>> io.print(X, !IO), io.nl(!IO).
>>
>> :- pred test(list(int)::in) is semidet.
>> test([]).
>> test([X | Xs]) :-
>> X < 5,
>> test(Xs).
>>
>> Is it defined that test/1 is tail recursive?
>
> It depends how you are compiling it. If you're using a hlc grade
> and invoke the compiler with --no-optimize-tailcalls, then definitely
> not!
>
> Assuming you're not doing something like that then yes, the above
> will be compiled into tail recursive code; if you want to make sure
> then ask the compiler, e.g. invoke it with
> --warn-non-tail-recursion=self.
>
> (We also have pragma versions of that warning, although they are
> currently undocumented. If you put
>
> :- pragma require_tail_recursion(test/1, [error]).
>
> in your program, then the compiler will emit an error if test/1
> is not going to compiled in a way that is tail recursive.)
OK, cool.
>> It seems to be just as valid for it to walk to the end of the list,
>> hit the [], and then walk backwards to test 3 < 5, 2 < 5, 1 < 5.
>
> It would be valid, but there's no reason for the compiler to re-arrange
> the code that way.
OK, but what if the code is instead
test([X | Xs]) :-
test(Xs),
X < 5.
Normally I read Mercury code as if conjunction order doesn't matter at
all, but
if it does matter to tail recursive code (without semantics flags to
disable
reordering), then I still have to think about order to an extent. At
least I
should have a style rule like "put tail calls at the end".
> Julien.
More information about the users
mailing list