Prolog nth1 anonymous variables
Asked Answered
L

3

8

I have a List with Integers and anonymous variables and I try to find the index of a special values. Problem is as soon I'm using nth1/3 to find the indices Prolog assigns values to the anonymous variables and therefore I find way too indices.

Example: List = [1,\_,1], where I want as result X = 1, X = 3 from nth1(X,List,1), but as stated before I get X = 1, X = 2, X = 3.

Lamellicorn answered 15/5, 2017 at 17:25 Comment(4)
Anonymous variables are quite problematic in the toplevel. So you get the same as for, say _A except that you are not shown that answer substitutionJaimiejain
@lurker May be dif/2 instead of \= ?Matrimonial
@Matrimonial good catch! but eck.... I meant (==)/2 not (\=)/2.Budgerigar
easy: ?- L=[1,_,1],nth1(X,L,V),V==1. L = [1, _7064, 1], X = V, V = 1 ; L = [1, _7064, 1], X = 3, V = 1. Beryllium
G
5

There is a somewhat problematic issue hidden in your requirements: They violate an important declarative property called monotonicity. By this we mean that adding constraints can at most make the solution more specific, never more general.

For example, with the solution you posted, we get:

?- list_el_index([_], 1, N).
false.

Now I add a constraint by imposing an additional requirement on the hitherto free anonymous variable:

?- Var = 1, list_el_index([Var], 1, N).
Var = 1,
N = 0 .

I mean: Come on! We have added a constraint, and as a result get more solutions than before? Such a result is unfortunate and prevents us from reasoning in a logical way about this program.

The program also fails us in other respects. For example, let us ask: Which solutions are there at all?

?- list_el_index(Ls, El, I).
nontermination

Ideally, we would like the program to generate solutions in such cases! This generality is one of the foremost attractions of logic programming, and distinguishes it from more low-level paradigms.


One way to solve such issues is to symbolically distinguish the different kinds of elements that appear in your list.

For example, let us use:

  • u for an unknown value.
  • i(I) for an integer I.

With this new representation, your solution becomes:

list_el_index([i(I)|_], I, 0).
list_el_index([_|Tail], Element, Index) :-
    list_el_index(Tail, Element, Index0),
    Index #= Index0+1.

I have also taken the liberty to replace (is)/2 by (#=)/2, to advertise and stick to more general integer arithmetic that lets us more freely reorder the goals, if necessary. Depending on your Prolog implementation, you may have to import a library to benefit from (#=)/2.

With this representation, your initial case becomes:

?- list_el_index([i(1),u,i(1)], 1, Index).
Index = 0 ;
Index = 2 ;
false.

This works as desired!

Importantly, we can use the predicate also more generally, namely to generate possible answers:

?- list_el_index(Ls, El, I).
Ls = [i(El)|_2994],
I = 0 ;
Ls = [_2992, i(El)|_3000],
I = 1 ;
Ls = [_2992, _2998, i(El)|_3006],
I = 2 ;
Ls = [_2992, _2998, _3004, i(El)|_3012],
I = 3 .

Due to the program's monotonicity, we can fairly enumerate solutions by iterative deepening:

?- length(Ls, _), list_el_index(Ls, El, I).
Ls = [i(El)],
I = 0 ;
Ls = [i(El), _4812],
I = 0 ;
Ls = [_4806, i(El)],
I = 1 ;
Ls = [i(El), _4812, _4818],
I = 0 ;
etc.

This has become possible by using a representation that lets us distinguish the cases by pattern matching. Consider using this approach to make your programs usable in all directions, and to make logical reasoning applicable. It is quite easy to apply by using the appropriate wrapper or constant, and greatly increases the generality of your programs.

Getter answered 15/5, 2017 at 20:50 Comment(0)
M
2

This works :

 - L = [1,_,1], nth1(X, L, Y), ground(Y), Y= 1.
L = [1,_310914,1],
X = Y, Y = 1 ;
L = [1,_310914,1],
X = 3,
Y = 1.
Matrimonial answered 15/5, 2017 at 19:52 Comment(0)
L
1

Thanks to lurkers hint, I came up with this solution.

list_el_index([El1|_], El2, 0) :-
    El1 == El2.
list_el_index([_|Tail], Element, Index) :-
    list_el_index(Tail, Element, Index1),
    Index is Index1+1.
Lamellicorn answered 15/5, 2017 at 19:54 Comment(2)
Yes, because it should be list_el_index(L,1,X).Lamellicorn
Ok you don't use nth1 signature !Matrimonial

© 2022 - 2024 — McMap. All rights reserved.