prologlogical-purityprolog-coroutining

Coroutining in Prolog: when argument is a list (it has fixed length)


Question

Is it possible to schedule a goal to be executed as soon as the length of a list is known / fixed or, as @false pointed out in the comments, a given argument becomes a [proper] list? Something along this line:

when(fixed_length(L), ... some goal ...).

When-conditions can be constructed using ?=/2, nonvar/1, ground/1, ,/2, and ;/2 only and it seems they are not very useful when looking at the whole list.

As a further detail, I'm looking for a solution that presents if that is possible.

Motivation

I think this condition might be useful when one wants to use a predicate p(L) to check a property for a list L, but without using it in a generative way.

E.g. it might be the case that [for efficiency or termination reasons] one prefers to execute the following conjunction p1(L), p2(L) in this order if L has a fixed length (i.e. L is a list), and in reversed order p2(L), p1(L) otherwise (if L is a partial list).

This might be achieved like this:

when(fixed_length(L), p1(L)), p2(L).

Update

I did implement a solution, but it lacks purity.


Solution

  • It would be nice if when/2 would support a condition list/1. In the meantime, consider:

    list_ltruth(L, Bool) :-
       freeze(L, nvlist_ltruth(L, Bool)).
    
    nvlist_ltruth(Xs0, Bool) :-
       (  Xs0 == [] -> Bool = true
       ;  Xs0 = [_|Xs1] -> freeze(Xs1, nvist_ltruth(Xs1, Bool))
       ;  Bool = false
       ).
    
    when_list(L, Goal_0) :-
       nvlist_ltruth(L, Bool),
       when(nonvar(Bool),( Bool == true, Goal_0 )).
    

    So you can combine this also with other conditions.

    Maybe produce a type error, if L is not a list.

       when(nonvar(Bool), ( Bool == true -> Goal_0 ; sort([], L) ).
    

    Above trick will only work in an ISO conforming Prolog system like SICStus or GNU that produces a type_error(list,[a|nonlist]) for sort([],[a|nonlist]), otherwise replace it by:

       when(nonvar(Bool),
          ( Bool == true -> Goal_0 ; throw(error(type_error(list,L), _)).
    

    Many systems contain some implementation specific built-in like '$skip_list' to traverse lists rapidly, you might want to use it here.