Page 1 of 1

Nested foreach

Posted: 16 Sep 2015 9:51
by Ferenc Nagy
Hi,
I'd rather start a new thread about the

Code: Select all

foreach...end foreach
construct instead of continue the "universal quantification http://discuss.visual-prolog.com/viewtopic.php?t=14323"
thread.

1) Are
A)

Code: Select all

foreach nondetpred1(X) do      foreach nondetpred2(X,Y) do          foreach nondetpred3(X,Y,Z) do              procbody(X,Y,Z)          end foreach      end foreach end foreach,
and

B)

Code: Select all

foreach nondetpred1(X),      foreach nondetpred2(X,Y),          foreach nondetpred3(X,Y,Z) do              procbody(X,Y,Z)          end foreach      end foreach end foreach,
equivalent?
I mean: Yes, they are.

The

Code: Select all

foreach...end foreach
,

Code: Select all

if then ...else...end if
constructs are newly added to the VIP syntax. I often add the illegal comma before the closing tag:

Code: Select all

foreach nondetpred3(X,Y,Z) do       procbody((X,Y,Z), % <=== syntax error end foreach.

Posted: 16 Sep 2015 11:08
by Martin Meyer
To the equivalence question: Every foreach must have its own do. So, A) is a legal construct (provided all used predicates are declared properly), but B) does not compile.

To the comma issue: I am doing this mistake often too. But clearly there belongs no comma. A comma in that place would have the same meaning as an and. Evidently

Code: Select all

foreach nondetpred3(X,Y,Z) do     procbody(X,Y,Z) and end foreach.
does not make sense.

Many regards
Martin

Posted: 16 Sep 2015 11:10
by Thomas Linder Puls
B) is syntactically wrong.

But

Code: Select all

foreach nondetpred1(X) do     foreach nondetpred2(X,Y) do         foreach nondetpred3(X,Y,Z) do             procbody(X,Y,Z)         end foreach     end foreach end foreach,
is equivalent to

Code: Select all

foreach     nondetpred1(X),     nondetpred2(X,Y),     nondetpred3(X,Y,Z) do     procbody(X,Y,Z) end foreach,
if that is what you meant.

Which is the better progarming style

Posted: 16 Sep 2015 11:23
by Ferenc Nagy
Yes I meant so but I forgot the

Code: Select all

do
words.
Which is the better programing style, the nested

Code: Select all

foreach...do..end foreach
or the single

Code: Select all

foreach comma separated list of predicates do short body end foreach
?

Posted: 16 Sep 2015 12:56
by Martin Meyer
Surprisingly a difference between the coding variants is, that the 1st variant produces more backtrack points. Below test shows, that 1st variant produces 6 backtrack points, 2nd produces 4, and a 3rd variant using a generator-fail-loop produces also 4.

Code: Select all

class predicates     nondetpred1 : (unsigned X [out])         nondeterm. clauses     nondetpred1(X) :-         X = std::cIterate(2).   class predicates     nondetpred2 : (         unsigned X,         unsigned Y [out])         nondeterm. clauses     nondetpred2(_X, Y) :-         Y = std::cIterate(2).   class predicates     nondetpred3 : (         unsigned X,         unsigned Y,         unsigned Z [out])         nondeterm. clauses     nondetpred3(_X, _Y, Z) :-         Z = std::cIterate(2).   class predicates     procbody : (         unsigned X,         unsigned Y,         unsigned Z). clauses     procbody(X, Y, Z) :-         stdIo::write("(", X, ", ", Y, ", ", Z, " [", programControl::getBackTrackPoints(), "]", ") ").   class predicates     foreach_ : (         function_nd{Type} Gen,         predicate{Type} Body). clauses     foreach_(Gen, Body) :-         Item = Gen(),             Body(Item),             fail.     foreach_(_, _).   clauses     run() :-         stdIo::write("[", programControl::getBackTrackPoints(), "]\n"),         foreach nondetpred1(X) do             foreach nondetpred2(X, Y) do                 foreach nondetpred3(X, Y, Z) do                     procbody(X, Y, Z)                 end foreach             end foreach         end foreach,         stdIo::write("\n---\n"),         foreach             nondetpred1(X),                 nondetpred2(X, Y),                     nondetpred3(X, Y, Z) do                         procbody(X, Y, Z)         end foreach,         stdIo::write("\n---\n"),         foreach_(             {                 = tuple(X, Y, Z) :-                     nondetpred1(X),                         nondetpred2(X, Y),                             nondetpred3(X, Y, Z)             },             { (tuple(X, Y, Z)) :- procbody(X, Y, Z) }).
Regards
Martin

Posted: 16 Sep 2015 17:40
by Peter Muraya
Hi Frank and Martin,
I'm not sure how to interpret the number of backtracking points metric, i.e., whether the more the better or vice versa. I was not even aware of of the predicate programControl::getBackTrackPoints()

In my case, Im often guided by whether there is further processing I need to do after the end foreach or not. If there is, then the I use the first variant; otherwise I use the second one. For example:-

Code: Select all

foreach nondetpred1(X) do     foreach nondetpred2(X,Y) do         foreach nondetpred3(X,Y,Z) do             procbody(X,Y,Z)         end foreach,         do_something(),     end foreach,     do_something_else() end foreach

Posted: 16 Sep 2015 19:24
by Martin Meyer
Roughly speaking backtrack points cost space on the run stack. But stack usage is of course not the only measure of all things, when you have to opt for a coding variant.

Best regards
Martin

Posted: 17 Sep 2015 5:17
by Peter Muraya
Thanks Martin
So, you are using programControl::getBackTrackPoints() for optimization purporses; do you ever use it for other reasons?

Posted: 17 Sep 2015 8:40
by Martin Meyer
No, I never used programControl::getBackTrackPoints for other than test/info/optimization.

Regards
Martin