How to iterate over a structure?

If I have a list like: [atm(abd,bubu,ha), atm(aei),atm(xyz,huhu), atm(aabb,a,e,x)]

how can I "iterate over" the elements from one of the structures atm

?

For example, for atm(abd, bubu, ha)

I would like write

abd

, bubu

and ha

.

The problem is that structures are variable in length.

Is there a way to convert the struct to a list? Thank.

+3


source to share


2 answers


Sure.

If First

there is atm(abd,bubu,ha)

(for example), this code will split it into a list that you can go through.

First =.. List.

      



Then it List

will be [atm, abd, bubu, ha]

.

IDK if it works in your specific version of PROLOG. I am using SWI-PROLOG. If not, your version may have a similar predicate.

For more information see http://www.swi-prolog.org/pldoc/doc_for?object=(%3D..)/2 .

+2


source


Using (=..)/2

@TopologicalSort has already given a good answer, using (=..)/2

to convert the term to functor and argument list .

This, obviously, very often solves the immediate problem.

However, it also has its drawbacks: first, and most importantly, (=..)/2

it is not a general attitude. For example, we have:

? - X = .. Y.
 ERROR: Arguments are not sufficiently instantiated

This means that we cannot use this construct to generate solutions. It only works if its arguments are sufficiently instantiated.

Second, the use (=..)/2

also includes the time and memory overhead for building and presenting a list in addition to a term that already exists in a different form (And, mutatis & mutandis, in the other direction too, of course.)

So it might be worth asking: are there different ways to accomplish this task? Do they fit better?

Alternative 1: Manual execution

How do I convert? Let me count the paths.

In the example you cite, we should be able to process & mdash in the order they appear - terms of the following forms:

  • atm/3

  • atm/1

  • atm/2

  • atm/4

The point here is that the number of cases shown is finite , so we can easily deal with all of these:



atm_list (atm (A), [A]).
atm_list (atm (A, B), [A, B]).
atm_list (atm (A, B, C), [A, B, C]).
atm_list (atm (A, B, C, D), [A, B, C, D]).

To convert a list of such terms, you can use maplist/2

:

? - Ls = [atm (abd, bubu, ha), atm (aei), atm (xyz, huhu), atm (aabb, a, e, x)],
   maplist (atm_list, Ls, Lists).
Ls = [atm (abd, bubu, ha), atm (aei), atm (xyz, huhu), atm (aabb, a, e, x)],
Lists = [[abd, bubu, ha], [aei], [xyz, huhu], [aabb, a, e, x]].

The main advantage is that this relationship is very general and can also be used to generate responses:

? - atm_list (A, Ls).
A = atm (_27464, _27466, _27468),
Ls = [_27464, _27466, _27468];
A = atm (_27464),
Ls = [_27464];
A = atm (_27464, _27466),
Ls = [_27464, _27466];
A = atm (_27464, _27466, _27468, _27470),
Ls = [_27464, _27466, _27468, _27470].

It is also more efficient than using it (=..)/2

. It is clear that this can be done only if the number of arising cases is finite. ( Exercise : Write a Prolog program that generates sentences for all integers. 1..N).

Alternative 2: Using Lists

There are several well-known criteria for judging whether lists are an appropriate data structure. For example:

  • Does an empty list make sense in your use case?
  • Are there reasonable cases for all possible lengths?
  • and etc.

Only you can answer this question for your specific use case, so I am only showing how it might look: Suppose you represent your entire initial list like this:

[[abd, bubu, ha], [aei], [xyz, huhu], [aab, a, e, x]]

Then the whole problem doesn't even arise , because the elements are already specified as lists. So there is no need to convert anything anymore.

+3


source







All Articles