Search code examples
arrayslistprologeclipse-clp

Looping through a list which is a subarray


I'm using ECLiPSe 6.1. I have an array of variables of dimension N x N, let's call it Vars. Now I call a procedure with, say, my_procedure(Vars[1..N,1..2]).

Inside the procedure (my_procedure(List) :- ...), something like (foreach(X, List) do ...) is used. This doesn't work. I have to write something like L is List inside the procedure before looping over L (instead of List) to make it work.

Why is this? And how can I address it? Because later on I try to call the procedure with flatten(Vars[1..N,1..2]) and then it gets even worse.

I started using collection_to_list/2 (with flatten) to resolve the issue, but I was wondering if there's an elegant way to address it.


Solution

  • Let me elaborate a bit, because your question highlights a feature of Prolog/ECLiPSe that regularly surprises users coming from other programming languages:

    • Every term/expression is by default just a symbolic structure with no inherent meaning
    • Any interpretation/evaluation of a such symbolic structure only happens in particular contexts, or when requested explicitly

    Maybe the most blatant example is with what looks like an "arithmetic expression":

    ?- writeln(3+4).
    3 + 4
    

    Prolog takes the argument 3+4 simply as the symbolic term +(3,4) and passes it to writeln/1, uninterpreted. Passing a term as an argument to a user-defined predicate doesn't change this, there is no implicit evaluation at call time:

    p(X) :- writeln(received(X)).
    
    ?- p(3+4).
    received(3 + 4)
    

    If we want to interpret the argument as an arithmetic expression and evaluate it, we have to request this explicitly:

    parith(Expr) :- Num is Expr, writeln(evaluated_to(Num)).
    
    ?- parith(3 + 4).
    evaluated_to(7)
    

    Array access expressions in ECLiPSe behave in the same way. They are just symbolic expressions until explicitly evaluated by a predicate that understands them:

    ?- Array = [](11,22,33), p(Array[2]).
    received([](11,22,33)[2])
    
    ?- Array = [](11,22,33), parith(Array[2]).
    evaluated_to(22)
    

    So, to finally come back to your original problem: when you call my_procedure(Vars[1..N,1..2]), the argument that gets passed is the symbolic expression Vars[1..N,1..2], and this is what my_procedure/1 receives. To turn that into the flat list that you want, it has to be interpreted as an expression that yields a list, and collection_to_list/2 (or, starting from ECLiPSe 7.0, eval_to_list/2) do exactly that:

    plist(Expr) :- eval_to_list(Expr, List), writeln(evaluated_to(List)).
    
    ?- A = [](11, 22, 33), p(A[2 .. 3]).
    received([](11, 22, 33)[2 .. 3])
    
    ?- A = [](11, 22, 33), plist(A[2 .. 3]).
    evaluated_to([22, 33])