didoudiaz / gprolog

GNU Prolog
Other
106 stars 13 forks source link

length/2 regression #7

Closed UWN closed 2 years ago

UWN commented 3 years ago

length(List, Length) now sometimes produces a type_error(list,_) when there is no instance of List that is a list. In the past, length/2 uniformly failed in this case, as specified by the template and mode length(?term, ?integer).

See #4 ff:

| ?- length(2,0). 
uncaught exception: error(type_error(list,2),top_level/0) % regression
| ?- length([_|2],0). 

no                                                        % expected
| ?- length([_|2],N). 
uncaught exception: error(type_error(list,2),top_level/0) % regression
| ?- length([_|2],1). 
uncaught exception: error(type_error(list,2),top_level/0) % regression
| ?- length([_,_|2],1). 

no                                                         % expected
pmoura commented 3 years ago

Related discussion: https://github.com/infradig/trealla/issues/233

pmoura commented 3 years ago

@didoudiaz the current Logtalk git version includes an extended test set for the length/2 predicate, which you may find useful to help ensure that all type errors in the first argument are detected/reported.

pmoura commented 2 years ago

A Prolog definition for the length/2 predicate that type-checks both arguments but makes no attempt to handle cyclic terms:

length(List, Length) :-
    (   var(Length) ->
        length(List, List, 0, Length)
    ;   \+ integer(Length) ->
        throw(error(type_error(integer,Length), length/2))
    ;   Length < 0 ->
        throw(error(domain_error(not_less_than_zero,Length), length/2))
    ;   make_list(Length, List, List)
    ).

make_list(N, Term, List) :-
    (   N =:= 0, Term = [] ->
        true
    ;   N < 0, var(Term) ->
        fail
    ;   M is N-1, Term = [_| Tail] ->
        make_list(M, Tail, List)
    ;   Term \= [],
        Term \= [_|_],
        throw(error(type_error(list,List), length/2))
    ).

length(Term, List, _, _) :-
    Term \= [],
    Term \= [_|_],
    throw(error(type_error(list,List), length/2)).
length([], _, Length, Length).
length([_| Tail], List, Acc, Length) :-
    Acc2 is Acc + 1,
    length(Tail, List, Acc2, Length).

This definition passes all Logtalk bundled tests.

pmoura commented 2 years ago

All tests now pass! 🎉🥳 Thanks for the fix. Making the behavior depending on the strict_iso flag is a good idea.