Prolog, access specific member of list?
-
07-07-2021 - |
문제
Can anyone tell me how to access a specific member of a list in prolog? Say for example I need to access the 3rd or 4th element of a list passed into a rule?
해결책
nth0(Ind, Lst, Elem)
or nth1(Ind, Lst, Elem)
with SWI-Prolog, nth0
the first element has the index 0.
For example,
nth0(3, [a, b, c, d, e], Elem). %Binds d to Elem
nth1(3, [a, b, c, d, e], Elem). %Binds c to Elem
nth0(Ind, [a, b, c, d, e], d). %Binds 3 to Ind
nth0(3, [a, b, c, X, e], d). %Binds d to X
nth0(3, [a, b, c, d, e], c). %Fails.
다른 팁
When the indexes you need to access are so small, you could use pattern matching. Say we need the third element or fourth:
third([_,_,E|_], E).
fourth([_,_,_,E|_], E).
This could be more useful if used 'inline', when the list carries info with positional relevance. For instance
your_rule([_,_,E|Rest], Accum, Result) :-
Sum is Accum + E,
your_rule(Rest, Sum, Result).
...
A prolog list is a classic list. Access is not direct. You have to iterate over to to find what you need.
You can get the nth element this way:
foo( [X1,X2,X3,X4,...,XN|Xs] ) :- ...
where [code]X[/code]n is the nth element of the list. Impractical for n larger than a small value. This is roughly analogous to a C/C++ pointer expression:
LLNode *nthElement = root->next->...->next ;
Otherwise, you have to iterate over the list to find the desired element, using a built-in predicate or a home-brew predicate, something like:
foo(Xs) :- nth_element(Xs,9,X) , ...
nth_element(Xs,N,X) :- nth_element(Xs,0,N,X) .
nth_element([X|Xs],N,N,X) :- !. nth_element([_|Xs],T,N,X) :- T1 is T+1 , nth_element(Xs,T1,N,X).
Using the func
library for SWI-Prolog, it is possible to write list comprehensions in a more concise way:
:- use_module(library(func)).
nth0((Index, List), Result) :-
nth0(Index,List,Result).
Now, you can access two elements of the list and add them together like this:
example :-
List = [1,5,12,9],
Y is (nth0 $ (0, List)) + (nth0 $(3,List)), %add the 1st and 4th elements of this list
writeln(Y). %prints 10