Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

foreach for Prolog

1,079 views
Skip to first unread message

neng...@gmail.com

unread,
Jun 8, 2009, 7:17:03 PM6/8/09
to
One of the new features I have been adding into B-Prolog version 7.3
is a built-in named foreach for describing loops. This was a by-
product of a project that tried to develop programs in CLP(FD) for the
benchmark problems used in the second ASP solver competition. Without
such a built-in, many problems would simply be too tedious to
describe. Here is the description of the built-in I added into B-
Prolog.

http://probp.com/manual/node35.html

and here are two example programs using foreach:

http://probp.com/examples/staircase.pl
http://probp.com/examples/magic.pl

Currently, foreach is interpreted and hence, as you can imagine, the
performance is poor. I am working on a compiler to compile foreach
into recursion. I'll make this compiler available if there is
interest.

I know I am not the first one who have realized the need for such a
built-in. ECLiPSe has various kinds of iterative constructs, but they
seem to be too difficult for me to use. I also know that I could be
doing more harm than good if no other system agrees to support similar
built-ins. Is it possible for the Prolog implementors to come up with
some de facto standard? I am not considering proposing this to ISO
because it might take 100 years to have this approved.

Cheers,
Neng-Fa

A.L.

unread,
Jun 8, 2009, 7:59:22 PM6/8/09
to
On Mon, 8 Jun 2009 16:17:03 -0700 (PDT), neng...@gmail.com wrote:

>I know I am not the first one who have realized the need for such a
>built-in. ECLiPSe has various kinds of iterative constructs, but they
>seem to be too difficult for me to use.

It seems that SICstus will have these constricts implemented as
standard feature

A.L.

sleeping...@yahoo.com

unread,
Jun 8, 2009, 11:34:25 PM6/8/09
to
On Jun 8, 11:17 pm, neng.z...@gmail.com wrote:
> One of the new features I have been adding into B-Prolog version 7.3
> is a built-in named foreach for describing loops.

Have you taken a look at the "Logical Loops" paper by Joachim
Schimpf?
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.6.9498

"We present a concrete proposal for enhancing Prolog and Prolog based
Constraint Logic Programming languages with a new language construct,
the logical loop. This is a shorthand notation for the most commonly
used recursive control structure: the iteration or tail recursion."

Jan Wielemaker

unread,
Jun 9, 2009, 5:10:30 AM6/9/09
to

It reminds me of a number of other topics in the community that never
settled. Examples are named-fields in compound terms, arrays, mutable
datastructures, etc. We all feel they should have a place in Prolog,
but nobody proposed a solution that convinced others.

Some of these primitives fit poorly in Prolog. This is notably true
for mutable state. How to deal with arrays in Prolog depends on `how
mutable' they are. The second issue is syntax. Arrays and
named-fields are typical examples of features that ask for additional
syntax. Many people simply would like to be able to write A[23] or
A->name (or A.name), Pure syntax-wise these are already hard to
realise. Allowing for A[23] is doable, but implementers are
(rightfully) reluctant to give up the current agreement on basic
Prolog syntax. A->name and A.name are both cumbersome. -> is already
an operator. . is the end-of-clause. Ok, A.name can work, but
"A. name" would break. Even then, the term-representation is the same
as [A|name], which is confusing and will lead to ambiguous cases.
Even if we find a way around that, the problem is that this type of
notation works great in functional languages, but poorly in the
relational Prolog language.

Possibly we should have a face-to-face brainstorming session with a
number of people who have spent work on these issues, want to be
pragmatic and are in a position to make decisions?

Sorry, just my $0.001

--- Jan

Ulrich Neumerkel

unread,
Jun 9, 2009, 9:05:44 AM6/9/09
to
Jan Wielemaker <j...@nospam.ct.xs4all.nl> writes:
>On 2009-06-09, sleeping...@yahoo.com <sleeping...@yahoo.com> wrote:
>> On Jun 8, 11:17 pm, neng.z...@gmail.com wrote:
>>> One of the new features I have been adding into B-Prolog version 7.3
>>> is a built-in named foreach for describing loops.
>>
>> Have you taken a look at the "Logical Loops" paper by Joachim
>> Schimpf?
>> http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.6.9498
>>
>> "We present a concrete proposal for enhancing Prolog and Prolog based
>> Constraint Logic Programming languages with a new language construct,
>> the logical loop. This is a shorthand notation for the most commonly
>> used recursive control structure: the iteration or tail recursion."
...
>Some of these primitives fit poorly in Prolog. ...

Above loop construct, while very powerful, uses red cuts.

> ... The second issue is syntax. ...

Before talking about extensions, why not start first to harmonize
syntax in existing code?

Currently, most Prolog systems rely heavily on a non-13211-1 syntax
feature. Namely the solo character | (head tail separator) as
infix operator.

Consider: (1;2|3;4).

Meaning:
;(1,'|'(2,;(3,4))).
'|'(;(1, 2), ;(3, 4)).
;(1,;(2,;(3,4))).
error

Above is YAP and BProlog, then SWI, then SICStus and XSB, finally
GNU Prolog.

Note that strict 13211-1 does not even allow the declaration of |
as an operator, since | is not an atom. You can only declare '|' - but
then you have to write 1'|'2. to use it.

Having | as infix, is thus an implementation specific extension of
13211-1.

The | as infix operator is heavily used in DCGs and CHRs. So agreeing
on a common extension would stabilize things a bit.


neng...@gmail.com

unread,
Jun 9, 2009, 9:55:54 AM6/9/09
to
On Jun 8, 11:34 pm, sleepingsquir...@yahoo.com wrote:
> On Jun 8, 11:17 pm, neng.z...@gmail.com wrote:
>
> > One of the new features I have been adding into B-Prolog version 7.3
> > is a built-in named foreach for describing loops.
>
>     Have you taken a look at the "Logical Loops" paper by Joachim
> Schimpf?

I started by reading ECLiPSe's manual, trying to import something from
there. I did like the array notations used in ECLiPSe, but I didn't
like the loop constructs (there are over ten different constructs and
I still don't know how to use param). I guess people may not like my
proposal either. That is why I posted it. I hope that we (I mean the
Prolog community) can come up with some sort of standard that will be
supported by all Prolog implementations.

Cheers,
Neng-Fa

A.L.

unread,
Jun 9, 2009, 10:45:42 AM6/9/09
to
On Tue, 9 Jun 2009 06:55:54 -0700 (PDT), neng...@gmail.com wrote:

>On Jun 8, 11:34�pm, sleepingsquir...@yahoo.com wrote:
>> On Jun 8, 11:17 pm, neng.z...@gmail.com wrote:
>>
>> > One of the new features I have been adding into B-Prolog version 7.3
>> > is a built-in named foreach for describing loops.
>>
>> � � Have you taken a look at the "Logical Loops" paper by Joachim
>> Schimpf?
>
>I started by reading ECLiPSe's manual, trying to import something from
>there. I did like the array notations used in ECLiPSe, but I didn't
>like the loop constructs (there are over ten different constructs and
>I still don't know how to use param).

Did you read paper by Joachim Shipmf? I believe that this paper is
clear enough.

What regards having/not having loops in Prolog: this is the issue what
is more convenient and intuitive for you: thinking in terms of
iterations or in terms of recursion.

I prefer recursion, and I am trying to avoid loops, unless, well...
they are really fit to the problem I am currently solving. Almost all
my test code is using loops, because using loops I can use "one liner"
that otherwise would rewire half page of code.

From design perspective, I believe that Prolog Loops is a masterpiece,
and (although, as I said, I don't like them very much) I will consider
loops important and welcomed adition to SICStus Prolog

A.L.

Jan Wielemaker

unread,
Jun 9, 2009, 3:07:29 PM6/9/09
to
On 2009-06-09, A.L <alew...@aol.com> wrote:
> On Tue, 9 Jun 2009 06:55:54 -0700 (PDT), neng...@gmail.com wrote:
>
>>On Jun 8, 11:34�pm, sleepingsquir...@yahoo.com wrote:
>>> On Jun 8, 11:17 pm, neng.z...@gmail.com wrote:
>>>
>>> > One of the new features I have been adding into B-Prolog version 7.3
>>> > is a built-in named foreach for describing loops.
>>>
>>> � � Have you taken a look at the "Logical Loops" paper by Joachim
>>> Schimpf?
>>
>>I started by reading ECLiPSe's manual, trying to import something from
>>there. I did like the array notations used in ECLiPSe, but I didn't
>>like the loop constructs (there are over ten different constructs and
>>I still don't know how to use param).
>
> Did you read paper by Joachim Shipmf? I believe that this paper is
> clear enough.

The paper is good (and so was the presentation in my memory).

> What regards having/not having loops in Prolog: this is the issue what
> is more convenient and intuitive for you: thinking in terms of
> iterations or in terms of recursion.
>
> I prefer recursion, and I am trying to avoid loops, unless, well...
> they are really fit to the problem I am currently solving. Almost all
> my test code is using loops, because using loops I can use "one liner"
> that otherwise would rewire half page of code.

Typically, that would be a good reason to go for loops.

> From design perspective, I believe that Prolog Loops is a masterpiece,
> and (although, as I said, I don't like them very much) I will consider
> loops important and welcomed adition to SICStus Prolog

I just did a little experiment, getting the max of a list. In Prolog
we have (none of these are tested, but I assume they are all `about'
right):

maxlist([M0|T], M) :-
maxlist(T, M0, M).

maxlist([], M, M).
maxlist([H|T], M0, M) :-
( M0 > H
-> maxlist(T, M0, M)
; maxlist(H, M0, M)
).


Using the ECLiPSe loops, we get this

maxlist([X0|Xs], Max) :-
( foreach(X,Xs), fromto(X0,M0,M1,Max) do
( X > M0 -> M1 = X ; M1 = M0 )
).

And if I understand the B-Prolog proposal right, we get

maxlist([H|T], Max) :-
foreach(X in T, ac(M,H), (X > M^0 -> M^1 = X ; M^1 = M^0)).

================================================================
In my observation, going down the list:

* The implementations use less lines
* The lines get longer
* The code gets less readable

In other words, I'm still not convinced :-( SICStus 4 using the ECLiPSe
Logical Loops convinces me a bit as Mats is generally quite good at
eliminating bullshit. Still, I'd like to see and hear about real
(= non-prolog-vendor) user experience.

Cheers --- Jan

Jan Wielemaker

unread,
Jun 9, 2009, 3:22:06 PM6/9/09
to
On 2009-06-09, Ulrich Neumerkel <ulr...@mips.complang.tuwien.ac.at> wrote:

> Jan Wielemaker <j...@nospam.ct.xs4all.nl> writes:
>> ... The second issue is syntax. ...
>
> Before talking about extensions, why not start first to harmonize
> syntax in existing code?
>
> Currently, most Prolog systems rely heavily on a non-13211-1 syntax
> feature. Namely the solo character | (head tail separator) as
> infix operator.
>
> Consider: (1;2|3;4).
>
> Meaning:
> ;(1,'|'(2,;(3,4))).
> '|'(;(1, 2), ;(3, 4)).
> ;(1,;(2,;(3,4))).
> error
>
> Above is YAP and BProlog, then SWI, then SICStus and XSB, finally
> GNU Prolog.

YAP and SWI do the same, except that in SWI the operators have different
priorities. Both do so to support the old |-for-disjunction operator.
SICStus does the backward compatibility mapping at the syntactic level
and SWI (and I guess YAP) do it in the compiler. GNU is strict ISO.

But ... what is the point? Its hard to get these things resolved and
resolving them makes very few people outside the ISO group happy. I
think YAP has the most sensible approach. I wonder why SWI has different
priorities (1105 and 1100). Its probably something from lost memories
...

> Note that strict 13211-1 does not even allow the declaration of |
> as an operator, since | is not an atom. You can only declare '|' - but
> then you have to write 1'|'2. to use it.
>
> Having | as infix, is thus an implementation specific extension of
> 13211-1.
>
> The | as infix operator is heavily used in DCGs and CHRs. So agreeing
> on a common extension would stabilize things a bit.

So why did ISO forbid this and make it impossible to support it as a
backward compatible feature?

Cheers --- Jan

Wit Jakuczun

unread,
Jun 9, 2009, 3:34:28 PM6/9/09
to
On 9 Cze, 21:07, Jan Wielemaker <j...@nospam.ct.xs4all.nl> wrote:

> In my observation, going down the list:
>
>         * The implementations use less lines
>         * The lines get longer
>         * The code gets less readable
>
> In other words, I'm still not convinced :-( SICStus 4 using the ECLiPSe
> Logical Loops convinces me a bit as Mats is generally quite good at
> eliminating bullshit.  Still, I'd like to see and hear about real
> (= non-prolog-vendor) user experience.
>

My story:
- When I was starting with Prolog (ECLiPSe) I thought that loops are
great thing. Prolog was not that scary. With loops it looked
like "good" old C :)
- After sometime I realized that logical loops are not the same loops
I knew from C. I could some magical tricks...
- Finally I found that my code looked like ugly C code written in
Prolog.
There is a saying: In any language one can program in C... and this
was
my case.
- I forced myself not to use loops. This resulted in more clear code
and
more confidence in using Prolog.
- Now I do not use loops for regular code. They are left only for
quick
"dirty" hacks (like printing a list), mainly for debugging
purposes.

The conclusion is that logical loops are not good for beginers
although
they (the beginners) could think so.

Best regards,
Wit Jakuczun [ http://wlogsolutions.com ]

Mats Carlsson

unread,
Jun 9, 2009, 3:50:17 PM6/9/09
to
On Jun 9, 9:07 pm, Jan Wielemaker <j...@nospam.ct.xs4all.nl> wrote:
> On 2009-06-09, A.L <alewa...@aol.com> wrote:

[...]

> Using the ECLiPSe loops, we get this
>
> maxlist([X0|Xs], Max) :-
> ( foreach(X,Xs), fromto(X0,M0,M1,Max) do
> ( X > M0 -> M1 = X ; M1 = M0 )
> ).

You can do a real one-liner (this one is tested!):

maxlist([X0|Xs], Max) :- (foreach(X,Xs), fromto(X0,M0,M1,Max) do M1
is max(M0,X)).

[...]

> SICStus 4 using the ECLiPSe Logical Loops convinces me a bit as Mats is generally quite good at eliminating bullshit.

Should I take that as a compliment?

Anyway, my motivation was (a) I finally got tired of writing little
auxiliary predicates for simple iterations; (b) several people whose
opinion I respect said that do loops are a Good Thing that they would
like to see in SICStus.
--Mats

Ulrich Neumerkel

unread,
Jun 9, 2009, 3:27:25 PM6/9/09
to
Jan Wielemaker <j...@nospam.ct.xs4all.nl> writes:
>On 2009-06-09, Ulrich Neumerkel <ulr...@mips.complang.tuwien.ac.at> wrote:
>> Jan Wielemaker <j...@nospam.ct.xs4all.nl> writes:
>>> ... The second issue is syntax. ...
>>
>> Before talking about extensions, why not start first to harmonize
>> syntax in existing code?
>>
>> Currently, most Prolog systems rely heavily on a non-13211-1 syntax
>> feature. Namely the solo character | (head tail separator) as
>> infix operator.
>>
>> Consider: (1;2|3;4).
>>
>> Meaning:
>> ;(1,'|'(2,;(3,4))).
>> '|'(;(1, 2), ;(3, 4)).
>> ;(1,;(2,;(3,4))).
>> error
>>
>> Above is YAP and BProlog, then SWI, then SICStus and XSB, finally
>> GNU Prolog.
>
>YAP and SWI do the same, except that in SWI the operators have different
>priorities. Both do so to support the old |-for-disjunction operator.

There are more differences between them - see below.

>SICStus does the backward compatibility mapping at the syntactic level
>and SWI (and I guess YAP) do it in the compiler. GNU is strict ISO.

In DCGs, | is quite common as this corresponds to EBNF notation.
I would not consider this a case of backward compatibility.

>But ... what is the point? Its hard to get these things resolved and
>resolving them makes very few people outside the ISO group happy. I
>think YAP has the most sensible approach. I wonder why SWI has different
>priorities (1105 and 1100). Its probably something from lost memories
>...

Removing this difference would be a step towards covergence and improved
compatibilty.

>> Note that strict 13211-1 does not even allow the declaration of |
>> as an operator, since | is not an atom. You can only declare '|' - but
>> then you have to write 1'|'2. to use it.
>>
>> Having | as infix, is thus an implementation specific extension of
>> 13211-1.
>>
>> The | as infix operator is heavily used in DCGs and CHRs. So agreeing
>> on a common extension would stabilize things a bit.
>
>So why did ISO forbid this and make it impossible to support it as a
>backward compatible feature?

13211-1 allows this as an implementation specific extension. So
ISO does not make this impossible, quite the contrary.

I do not know when | as infix in DCGs became popular. At least the
DEC-10 manual (1978), textbooks like Coelho, Cotta & Pereira (1980),
Clocksin & Mellish (1981), Kluzniak & Szpakowicz (1985), Sterling &
Shapiro (1986), Pereira & Shieber (1987) all do not mention | for
alternation in DCGs. It seems, the first book mentioning it is
O'Keefe (1990).

Further, there were entirely incompatible usages of infix |:

a) disjunction in DEC-10
b) commit in Concurrent Prolog and descendants
(also advocated for Prolog in the 1980s)
c) list syntax in some systems: (a|b) stood for [a|b]

Time changes, and today I cannot see c in use. On the other
hand there are uses of | as infix. Maybe we can resolve this?

There are still some more technical details here: For example,
YAP and SICStus only permit | as an infix operator. I.e.,
|||. f(|). f((|)). [a|b|c]. are invalid (but parsed in SWI).
When redefining | as prefix, only '|'1. is permitted, but not
as in SWI |1.

neng...@gmail.com

unread,
Jun 9, 2009, 7:45:38 PM6/9/09
to

Let me tell you my personal experience, both as a programmer and an
educator. I had thought about implementing foreach many times before
but had never decided to do so because I always had time to use
recursion. When I started writing programs for the ASP competition
problems, I realized that I couldn't afford the time. Just consider
the maze generation program:

www.sci.brooklyn.cuny.edu/~zhou/aspcompetition/maze.pl

it would take me more time to write this program usign recursion than
writing the interpreter! I can't imagine anybody can write a more
readable program using recursion than this one.

As an educator, I believe that Prolog would be more acceptable to
beginners had Prolog had something like foreach. All our students
learn OOP first and they are used to using the enhanced for statement
of Java or the foreach statement of C#. I could do an experiment bring
my proposal to my next class and seeing what my students think about
it.

Cheers,
Neng-Fa

Joachim Schimpf

unread,
Jun 9, 2009, 10:16:26 PM6/9/09
to
neng...@gmail.com wrote:
> On Jun 8, 11:34 pm, sleepingsquir...@yahoo.com wrote:
>> On Jun 8, 11:17 pm, neng.z...@gmail.com wrote:
>>
>>> One of the new features I have been adding into B-Prolog version 7.3
>>> is a built-in named foreach for describing loops.
>> Have you taken a look at the "Logical Loops" paper by Joachim
>> Schimpf?
>
> I started by reading ECLiPSe's manual, trying to import something from
> there.

If you read the paper, this will hopefully clarify some of my design
decisions. It is here, with corresponding slide set and code:

http://eclipse-clp.org/software/loops/index.html


> I did like the array notations used in ECLiPSe, but I didn't
> like the loop constructs (there are over ten different constructs and
> I still don't know how to use param).

There is really only one construct called do/2, and only one of the
many iteration specifiers you refer to is really fundamental. Let me
present it in a way that is different from the paper, and may appeal
more to the purist.

A call

?- ( fromto(From,In,Out,To) do Body ).

is translated into

?- do__1(From, To).

do__1(Last, Last) :- !.
do__1(In, Last) :- Body, do__1(Out, Last).

That's more or less all there is to it. Ok, one important thing:
you can have arbitrarily many fromto-specifiers in the same do-loop.
For each of them, you will simply get an additional argument pair in
the generated predicate. So, every fromto maps to one accumulator
in the recursion.

Equipped with this, you can already write all your iterative recursions
as do-loops. But of course there are some very common patterns, like
iteration over list elements or integers, for which one can have
intuitive abbreviations, that's why we have additional notation like

?- ( foreach(X,List) do ... ).
as shorthand for
?- ( fromto(List,[X|Xs],Xs,[]) do ... ).

?- ( for(I,L,H) do ...).
as shorthand for
?- H1 is H+1, ( fromto(L,I,I1,H1) do I1 is I+1, ... ).

?- ( param(S) do ... ).
as shorthand for
?- ( fromto(S,S,S,_) do ... ).

?- ( foreacharg(X,S) do ... ).
as shorthand for
?- N1 is arity(S)+1, ( fromto(1,I,I1,N1),param(S) do arg(I,S,X), I1 is I+1, ... ).

and so on.

These do-loops have been an official language feature of ECLiPSe since
1998, and over the years users have come with many requests to pack
more functionality into them. Some of these (in particular, giving
them more of a while-flavour) we have resisted, but some have been
integrated (the nested-loop features, which are not in the original paper).


neng...@gmail.com wrote:
> ECLiPSe has various kinds of iterative constructs, but they
> seem to be too difficult for me to use.

I do not really see a dramatic difference to what you have done,
so I would be interested to hear why exactly you find ECLiPSe's
loops more difficult. Arguably, the ECLiPSe design is a bit simpler
than yours, because is has
(a) no distinction between iterators and accumulators, which
is more Prolog-like
(b) no special X^i syntax in the loop bodies, i.e. the translator
does not touch the loop body at all


> Currently, foreach is interpreted and hence, as you can imagine, the
> performance is poor. I am working on a compiler to compile foreach
> into recursion. I'll make this compiler available if there is
> interest.

If it's slow, then it will not be used, so compilation is essential.
Do-loops were designed to be implementable by simple goal-expansion,
code for it is at http://eclipse-clp.org/software/loops/index.html
This relates to decisions about variable scoping (and the much-hated
param() construct), but that's a topic for a separate post...

Also be prepared that, once people start using loops, they will write
HUGE loops, so metacalling the bodies is not really an option.


Cheers,
Joachim

Joachim Schimpf

unread,
Jun 9, 2009, 10:31:15 PM6/9/09
to
Ulrich Neumerkel wrote:
> Jan Wielemaker <j...@nospam.ct.xs4all.nl> writes:
>> On 2009-06-09, sleeping...@yahoo.com <sleeping...@yahoo.com> wrote:
>>> On Jun 8, 11:17 pm, neng.z...@gmail.com wrote:
>>>> One of the new features I have been adding into B-Prolog version 7.3
>>>> is a built-in named foreach for describing loops.
>>> Have you taken a look at the "Logical Loops" paper by Joachim
>>> Schimpf?
>>> http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.6.9498
>>>
>>> "We present a concrete proposal for enhancing Prolog and Prolog based
>>> Constraint Logic Programming languages with a new language construct,
>>> the logical loop. This is a shorthand notation for the most commonly
>>> used recursive control structure: the iteration or tail recursion."
> ...
>> Some of these primitives fit poorly in Prolog. ...
>
> Above loop construct, while very powerful, uses red cuts.

They _can_be_ red. In most cases they aren't. They commit the
termination condition, in the same way the implicit cut in
if-then-else commits the conditional. The cut could be omitted,
but then you'd have to rely on extensive analysis to make sure
that the number of iterations is deterministic.


>
>> ... The second issue is syntax. ...
>
> Before talking about extensions, why not start first to harmonize
> syntax in existing code?

Why not start a new thread when changing topics?


Cheers,
Joachim

Joachim Schimpf

unread,
Jun 10, 2009, 12:53:01 AM6/10/09
to
Ulrich Neumerkel wrote:
> The | as infix operator is heavily used in DCGs and CHRs. So agreeing
> on a common extension would stabilize things a bit.

You are right about CHR, but for DCGs there is no problem with the
Cprolog/Quintus/Sicstus behaviour of regarding | as an alias for ;
There is no conflict, they are both interpreted as "or".

-- Joachim

Wit Jakuczun

unread,
Jun 10, 2009, 3:34:58 AM6/10/09
to
On 10 Cze, 01:45, neng.z...@gmail.com wrote:

> As an educator, I believe that Prolog would be more acceptable to
> beginners had Prolog had something like foreach. All our students
> learn OOP first and they are used to using the enhanced for statement

My statement is that students MUST first understand prolog without
loops. After this stage they are ready for using loops. If the first
stage is missing they will start writing in C in Prolog (I am assuming
here, that they have some experience with C-like languages).
But bear in mind that I have no experience as a prolog tutor.

> of Java or the foreach statement of C#. I could do an experiment bring
> my proposal to my next class and seeing what my students think about
> it.
>

They will prefer logical loops but because of the lack of experience.
I am using Prolog in business and I DO NOT use logical loops. The code
with
loops is less readable, less factorized, harder to maintain.
I DO use logical loops only when I am really short of time (as you
wrote)
or (much less frequently) I have to write some simple iterators.

Best regards,
Wit Jakuczun

Jan Wielemaker

unread,
Jun 10, 2009, 5:33:41 AM6/10/09
to
On 2009-06-09, Mats Carlsson <ma...@sics.se> wrote:
> On Jun 9, 9:07 pm, Jan Wielemaker <j...@nospam.ct.xs4all.nl> wrote:
> You can do a real one-liner (this one is tested!):
>
> maxlist([X0|Xs], Max) :- (foreach(X,Xs), fromto(X0,M0,M1,Max) do M1
> is max(M0,X)).

I know, but that simplification applies to all. AFAIK, the max/2
function is not part of ISO (yet?).

>> SICStus 4 using the ECLiPSe Logical Loops convinces me a bit as Mats is generally quite good at eliminating bullshit.
>
> Should I take that as a compliment?

Its meant that way :-) Quite often I agree to your judgement about
naming, argument order, functionality, etc.

> Anyway, my motivation was (a) I finally got tired of writing little
> auxiliary predicates for simple iterations; (b) several people whose
> opinion I respect said that do loops are a Good Thing that they would
> like to see in SICStus.

Interesting. I'm curious how it works out in practice. I.e,, how
many people actually keep using it, whether or not it makes the
language more accessible for novices/outsiders, etc.

There are surely domains where it is useful (like Neng-Fa's maze.pl).
The price is that -especially novices- will over-use it. I think that
would harm readability and code-reuse. Having to write

a(...) :-
....
maxlist(List, Max),
...

results in more easy to read code than

a(...) :-
....
(foreach(X, List), fromto(X0,M0,M1,Max) do M1 is max(M0,X)),
...

Roughly of course, the argument is comparable to or and if-then-else:
if you can give a sensible label to the in-lined construct the code
generally becomes easier to read by using a predicate. If not, an
if-then-else is easier to write and read, I see a *lot* of code out
there that (in my opinion) over-use these constructs.

Loops are slightly worse than or/if-then-else because I still think
they are syntactically awkward and their relation to native Prolog
is less obvious (certainly to the beginner).

Interesting ...

--- Jan

Ulrich Neumerkel

unread,
Jun 10, 2009, 6:49:12 AM6/10/09
to

The incompatibility becomes evident with nonterminals as
arguments and implementing the DCG expansion.

Also, generated Prolog texts are less interchangable between systems.

Ulrich Neumerkel

unread,
Jun 10, 2009, 6:54:44 AM6/10/09
to
Joachim Schimpf <jsch...@users.sourceforge.net> writes:
>Ulrich Neumerkel wrote:
>> Jan Wielemaker <j...@nospam.ct.xs4all.nl> writes:
>>> Some of these primitives fit poorly in Prolog. ...
>> Above loop construct, while very powerful, uses red cuts.
>
>They _can_be_ red. In most cases they aren't. They commit the
>termination condition, in the same way the implicit cut in
>if-then-else commits the conditional. The cut could be omitted,
>but then you'd have to rely on extensive analysis to make sure
>that the number of iterations is deterministic.

They are always red, if you go for the maximal generalization.
Consider your example on page 6, Section 4:

?- ( foreach(X,List), count(_,1,N), fromto(0,S0,S1,Sum) do
S1 is S0+1
).

You get here exactly one solution List = [].

If we now specialize this query by adding List = [_], we should
get fewer solutions (i.e. none). However

?- List = [_], ( see above ).

Now finds other solutions, while

?- ( see above ), List = [_].

fails.

A definition with explicit recursion would not have this problem.

Pure goals with instantiations that are too general - as in the
case above - either should produce all solutions or loop or
issue an instantiation error. Silent failure should always
mean that there is no solution.

A.L.

unread,
Jun 10, 2009, 8:32:07 AM6/10/09
to
On Tue, 9 Jun 2009 16:45:38 -0700 (PDT), neng...@gmail.com wrote:

>
>As an educator, I believe that Prolog would be more acceptable to
>beginners had Prolog had something like foreach. All our students
>learn OOP first and they are used to using the enhanced for statement
>of Java or the foreach statement of C#. I could do an experiment bring
>my proposal to my next class and seeing what my students think about

As educator, you should never teach beginners for-loops. The same
if-than-else

A.L.

Kish Shen

unread,
Jun 10, 2009, 11:23:23 AM6/10/09
to
Jan Wielemaker wrote:
>
>> Anyway, my motivation was (a) I finally got tired of writing little
>> auxiliary predicates for simple iterations; (b) several people whose
>> opinion I respect said that do loops are a Good Thing that they would
>> like to see in SICStus.
>
> Interesting. I'm curious how it works out in practice. I.e,, how
> many people actually keep using it, whether or not it makes the
> language more accessible for novices/outsiders, etc.
>

I think a lot of users of ECLiPSe use do loops, including Prolog novices
and users who have used other Prologs.

Speaking personally as a user who came to them after programming in
Prolog previously (they were already in ECLiPSe when I joined IC-Parc in
1998), I do continue to use do loops, especially for cases where only
the simple specifiers such as foreach are needed.

> There are surely domains where it is useful (like Neng-Fa's maze.pl).
> The price is that -especially novices- will over-use it. I think that
> would harm readability and code-reuse. Having to write
>
> a(...) :-
> ....
> maxlist(List, Max),
> ...
>
> results in more easy to read code than
>
> a(...) :-
> ....
> (foreach(X, List), fromto(X0,M0,M1,Max) do M1 is max(M0,X)),
> ...
>

To me, this example is easier to read because you are able to give a
sensible predicate name to maxlist/2. My experience is that coming up
with sensible names can be difficult in many cases.

The actual code for maxlist/2 is not easier to understand than the loop,
in my opinion. As Joachim mentioned in his post, the loop body is the
same code you would write in the body of the recursive goal, so I think
that in most cases the loop code should be readable as the recursive code.

In some cases, it may even be easier to understand, for example, the
specifier foreacharg, which iterates over the arguments of a structure,
you don't need to write all the support code (get the size of the
structure, getting each individual argument etc.).

On reusability: I often use loops that do something unique to the data I
am iterating over, so if I write this as an auxillary predicate, there
will be no reuse anyway.

Another different case is when the loop is doing something so trivial
that it is debatable if reusing the auxilary predicate will be really
useful. For example, setting a list of variables to 0:

(foreach(V,Vars) do V = 0)

[this can be written as (foreach(0, Vars) do true), but maybe this is
going to far]

The above example is taken from the eplex library in ECLiPSe. This is a
reasonably large program, of which the ECLiPSe source is about 5000
lines, and there is about 50 do loops.

> Roughly of course, the argument is comparable to or and if-then-else:
> if you can give a sensible label to the in-lined construct the code
> generally becomes easier to read by using a predicate. If not, an
> if-then-else is easier to write and read, I see a *lot* of code out
> there that (in my opinion) over-use these constructs.
>
> Loops are slightly worse than or/if-then-else because I still think
> they are syntactically awkward and their relation to native Prolog
> is less obvious (certainly to the beginner).
>

I think Joachim's post makes the relationship of ECLiPSe's do loop to
native Prolog quite clear. I agree that the need/use of param can be
awkward, but this may be an avoidable part of the way the loops are
transformed into Prolog code.

A rule of thumb I use is if I need to write one of more complicated
fromto specifier(s), then I may be better off writing an auxillary
recursive predicate directly.

Another consideration is that, because the loops are transformed into
auxilary predicates by the compiler, debugging can be a bit difficult.
This was one of the motivations for the loop_name specifier. However,
since we added source tracing to ECLiPSe 6.0, this is less of an issue
(and we spent quite a lot of effort to make sure the source tracing
works on macro-transformed code, mainly because of the do loops, but
also for DCGs and other things).

--Kish

Kish Shen

unread,
Jun 10, 2009, 12:17:57 PM6/10/09
to
Jan Wielemaker wrote:
>
> It reminds me of a number of other topics in the community that never
> settled. Examples are named-fields in compound terms, arrays, mutable
> datastructures, etc. We all feel they should have a place in Prolog,
> but nobody proposed a solution that convinced others.
>
> Some of these primitives fit poorly in Prolog. This is notably true
> for mutable state. How to deal with arrays in Prolog depends on `how
> mutable' they are. The second issue is syntax. Arrays and
> named-fields are typical examples of features that ask for additional
> syntax. Many people simply would like to be able to write A[23] or
> A->name (or A.name), Pure syntax-wise these are already hard to
> realise. Allowing for A[23] is doable, but implementers are
> (rightfully) reluctant to give up the current agreement on basic
> Prolog syntax. A->name and A.name are both cumbersome. -> is already
> an operator. . is the end-of-clause. Ok, A.name can work, but
> "A. name" would break. Even then, the term-representation is the same
> as [A|name], which is confusing and will lead to ambiguous cases.
> Even if we find a way around that, the problem is that this type of
> notation works great in functional languages, but poorly in the
> relational Prolog language.
>

As you probably know, ECLiPSe have both arrays notation and named
structure implemented. Personally I have not used array notation much,
but I do use the named structure notation a lot, and think it is very
important for writing and maintaining large programs. I would certainly
like to see some discussion on the way they are done in ECLiPSe, and see
them used in other Prologs (incorporating any good ideas from the
discussion, of course).

There probably no point in repeating here the ECLiPSe syntax here,
except to note that these are pure syntatic sugar (like the logical
loops) in the sense that they are source-to-source transformed back into
`normal' Prolog code (like loops).

I seem to remember that Joachim had originally intended to discuss the
named structures and possibly the array notation in his logical loop
paper, but ran out of room with just the logical loops, so no paper was
ever published on these other features of ECLiPSe....

--Kish

A.L.

unread,
Jun 10, 2009, 3:20:36 PM6/10/09
to
On Wed, 10 Jun 2009 17:17:57 +0100, Kish Shen <kish...@yahoo.com>
wrote:


>
>As you probably know, ECLiPSe have both arrays notation and named
>structure implemented. Personally I have not used array notation much,
>but I do use the named structure notation a lot, and think it is very
>important for writing and maintaining large programs. I would certainly
>like to see some discussion on the way they are done in ECLiPSe, and see
>them used in other Prologs (incorporating any good ideas from the
>discussion, of course).

SICStus Prolog has Object System that can be viewed a sort of
extension of named structure concept, but for me seems to me much more
powerful.

A.L.

Chip Eastham

unread,
Jun 11, 2009, 10:28:59 AM6/11/09
to
On Jun 8, 7:17 pm, neng.z...@gmail.com wrote:
> One of the new features I have been adding into B-Prolog version 7.3
> is a built-in named foreach for describing loops. This was a by-
> product of a project that tried to develop programs in CLP(FD) for the
> benchmark problems used in the second ASP solver competition. Without
> such a built-in, many problems would simply be too tedious to
> describe. Here is the description of the built-in I added into B-
> Prolog.
>
> http://probp.com/manual/node35.html
>
> and here are two example programs using foreach:
>
> http://probp.com/examples/staircase.pl
> http://probp.com/examples/magic.pl
>
> Currently, foreach is interpreted and hence, as you can imagine, the
> performance is poor. I am working on a compiler to compile foreach
> into recursion. I'll make this compiler available if there is
> interest.

Hi, Neng-Fa:

I know it's clear to you, but a bit more explicit
statement of when foreach/2-4 succeeds (and fails)
would clarify matters for the reader. You say the
call(Goal) is tried "for each" combination of the
iterators' outputs, so I assume this is logical
conjunction over all those goals, with no binding
of variables possible even if not corresponding
to iterators. [Your specification of renaming
all variables in Goal corresponding to iterators
makes it clear binding can't occur in those cases.]

Here's how I typically hand-code such "universal
quantification":

myConjunction(Data) :-
generateGoals(Data,Goal),
not(Goal),
!,
fail.
myConjunction(_).

By using the "double negation" to define universal
quantification in terms of "existence", I box
myself out from retrieving any bindings that
might occur. Typically this is okay because I'm
just running a bunch of tests to validate prior
bindings.

regards, chip

afa

unread,
Jun 11, 2009, 11:01:36 AM6/11/09
to
On Jun 8, 7:17 pm, neng.z...@gmail.com wrote:

> http://probp.com/manual/node35.html
>
> and here are two example programs using foreach:
>
> http://probp.com/examples/staircase.pl
> http://probp.com/examples/magic.pl
>
> Currently, foreach is interpreted and hence, as you can imagine, the
> performance is poor. I am working on a compiler to compile foreach
> into recursion. I'll make this compiler available if there is
> interest.

I have finished a compiler foreach/2-4. You can download the
interpreter and compiler from:

http://www.probp.com/download/foreach.pl
http://www.probp.com/download/compile_foreach.pl

The links have also been added to the manual page. They should work
with any major Prolog system (I tested them with B-Prolog, SWI, and
ECLiPSe).

Cheers,
Neng-Fa

afa

unread,
Jun 11, 2009, 11:37:38 AM6/11/09
to
On Jun 9, 10:16 pm, Joachim Schimpf <jschi...@users.sourceforge.net>
wrote:

ECLiPSe is one of the oldest CLP systems and is also the first Prolog
system that supports arrays. Naturally, you were the first to realize
the need for loop constructs. As more people write CLP programs and
use arrays, they will develop the same need.

I understand ECLiPSe's loop constructs better now. I think several
issues need to be addressed. First, the syntax is not so good. I don't
like the key word "do" in a logic loop construct, especially something
like "do true". Second, as Kish has mentioned, it goes too far to
enable iteration over lists that are yet to be constructed. Third,
debugging is an issue. The auxiliary predicates generated by the
compiler shouldn't occur in the trace.

The foreach I am proposing does not have these issues but has its own
issue. The biggest is, as you know, the goal needs to be transformed,
whether it is interpreted or compiled. When interpreted, it can be
very slow if the goal contains large terms. In the current
interpreter, arrays and hashtables are not touched but other terms do
need to be scanned. When compiled, it's not a problem because the term
is not big at compile time. Another issue is that local variables need
to be specified, even anonymous variables. This could be tedious if
there are many. The compiler can issue a warning if it finds a
variable that occurs in a foreach call only but is not declared as a
local variable.

> If it's slow, then it will not be used, so compilation is essential.
> Do-loops were designed to be implementable by simple goal-expansion,

I have just finished a compiler for foreach. It also runs on ECLiPSe.
Take a look at: http://www.probp.com/download/compile_foreach.pl.

Cheers,
Neng-Fa

Joachim Schimpf

unread,
Jun 12, 2009, 1:52:54 AM6/12/09
to
afa wrote:
>
> I understand ECLiPSe's loop constructs better now. I think several
> issues need to be addressed.

That may be true, but I don't think they are the ones you mention!


> First, the syntax is not so good. I don't
> like the key word "do" in a logic loop construct, especially something
> like "do true".

A trivial point, but I agree syntax is important. I did consider other
candidates for the name, in particular holds/2 and :/2. That would have
made many instances sound/look like mathematical quantifications, e.g.

foreach(X,Xs) holds X > 0
or
foreach(X,Xs) : X > 0

The colon wasn't really possible because it is overused already.
And with holds/2, I would have gotten even more complaints from
Ulrich for pretending to be logically clean. You could use holds/2
for a variant of do/2 that doesn't have a cut and can be nondeter-
ministic, but such a construct should probably not be called a loop.


> Second, as Kish has mentioned, it goes too far to
> enable iteration over lists that are yet to be constructed.

I think you refer to the fact that (unlike your proposal) I do not
distinguish iterators and aggregators/accumulators syntactically.
The main reason for this is to be closer to the Prolog spirit and
allow multidirectionality, i.e. a loop can work both ways:

?- Xs = [1, 2, 3], (foreach(X,Xs),foreach(Y,Ys) do succ(X, Y)).
Xs = [1, 2, 3]
Ys = [2, 3, 4]

?- Ys = [1, 2, 3], (foreach(X,Xs),foreach(Y,Ys) do succ(X, Y)).
Ys = [1, 2, 3]
Xs = [0, 1, 2]

This also means that you get more of the functionality of maplist/1,2,3,...
[Incidentally, this whole work was originally motivated by the desire
for "a better maplist"...]


> Third, debugging is an issue. The auxiliary predicates generated by the
> compiler shouldn't occur in the trace.

That's no different with your transformation. It is trivial to suppress
them, but you want to trace at least _something_, in order to be able to
skip over (the rest of) the iterations. It would of course be possible to
reverse-translate the aux-predicate calls to something that resembles more
closely the iteration specifiers.


>
> The foreach I am proposing does not have these issues but has its own
> issue. The biggest is, as you know, the goal needs to be transformed,
> whether it is interpreted or compiled. When interpreted, it can be
> very slow if the goal contains large terms. In the current
> interpreter, arrays and hashtables are not touched but other terms do
> need to be scanned. When compiled, it's not a problem because the term
> is not big at compile time. Another issue is that local variables need
> to be specified, even anonymous variables. This could be tedious if
> there are many. The compiler can issue a warning if it finds a
> variable that occurs in a foreach call only but is not declared as a
> local variable.

In the light of these rather serious issues, what's the big advantage
that makes them worthwhile? E.g. is there really a big advantage to
...ac(M,X0)... (X > M^0 -> M^1 = X ; M^1 = M^0)
with respect to
...fromto(X0,M0,M1,M)... ( X > M0 -> M1 = X ; M1 = M0 )
that justifies the introduction of a whole new ^-notation?


>
>> If it's slow, then it will not be used, so compilation is essential.
>> Do-loops were designed to be implementable by simple goal-expansion,
>
> I have just finished a compiler for foreach. It also runs on ECLiPSe.
> Take a look at: http://www.probp.com/download/compile_foreach.pl.
>
> Cheers,
> Neng-Fa


-- Joachim

Joachim Schimpf

unread,
Jun 12, 2009, 2:36:35 AM6/12/09
to
Ulrich Neumerkel wrote:
> Joachim Schimpf <jsch...@users.sourceforge.net> writes:
>> Ulrich Neumerkel wrote:
>>> Jan Wielemaker <j...@nospam.ct.xs4all.nl> writes:
>>>> Some of these primitives fit poorly in Prolog. ...
>>> Above loop construct, while very powerful, uses red cuts.
>> They _can_be_ red. In most cases they aren't. They commit the
>> termination condition, in the same way the implicit cut in
>> if-then-else commits the conditional. The cut could be omitted,
>> but then you'd have to rely on extensive analysis to make sure
>> that the number of iterations is deterministic.
>
> They are always red, if you go for the maximal generalization.

Hmmm, maybe the terminology is not clearly defined. I was referring
to the cuts being green for the intended modes. I feel supported
in this use of terminology by the following snippet of code from
Richard O'Keefe:

last_keys([], []) :- !. % Green cut for inverse use
last_keys([L|Ls], [K-L|KLs]) :-
last(K, L),
last_keys(Ls, KLs).

Maybe the property you talk about should be called evergreen.


> Consider your example on page 6, Section 4:
>
> ?- ( foreach(X,List), count(_,1,N), fromto(0,S0,S1,Sum) do
> S1 is S0+1
> ).
>
> You get here exactly one solution List = [].
>
> If we now specialize this query by adding List = [_], we should
> get fewer solutions (i.e. none). However
>
> ?- List = [_], ( see above ).
>
> Now finds other solutions, while
>
> ?- ( see above ), List = [_].
>
> fails.

We agree. As I said, the situation is like with if-then-else.
Substitute (List=[] -> true ; List=[_|_]) for (see above).


> A definition with explicit recursion would not have this problem.

A definition without cut would not have this problem, but should


probably not be called a "loop".

> Pure goals with instantiations that are too general - as in the
> case above - either should produce all solutions or loop or
> issue an instantiation error. Silent failure should always
> mean that there is no solution.

Yes. I'm looking forward to programming in Neumerkelog :-)


-- Joachim

A.L.

unread,
Jun 12, 2009, 8:55:35 AM6/12/09
to
On Tue, 09 Jun 2009 13:05:44 GMT, ulr...@mips.complang.tuwien.ac.at
(Ulrich Neumerkel) wrote:

>Jan Wielemaker <j...@nospam.ct.xs4all.nl> writes:
>>On 2009-06-09, sleeping...@yahoo.com <sleeping...@yahoo.com> wrote:
>>> On Jun 8, 11:17 pm, neng.z...@gmail.com wrote:
>>>> One of the new features I have been adding into B-Prolog version 7.3
>>>> is a built-in named foreach for describing loops.
>>>
>>> Have you taken a look at the "Logical Loops" paper by Joachim
>>> Schimpf?
>>> http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.6.9498
>>>
>>> "We present a concrete proposal for enhancing Prolog and Prolog based
>>> Constraint Logic Programming languages with a new language construct,
>>> the logical loop. This is a shorthand notation for the most commonly
>>> used recursive control structure: the iteration or tail recursion."
>...
>>Some of these primitives fit poorly in Prolog. ...
>
>Above loop construct, while very powerful, uses red cuts.

So what?...

A.L.

Peter Van Weert

unread,
Jun 12, 2009, 9:40:26 AM6/12/09
to
I believe the priority of `|' was changed because disjunctions in guards
of CHR rules parsed incorrectly.

Peter

afa

unread,
Jun 12, 2009, 11:32:49 AM6/12/09
to
On Jun 12, 1:52 am, Joachim Schimpf <jschi...@users.sourceforge.net>
wrote:

>
> That's no different with your transformation.  It is trivial to suppress
> them, but you want to trace at least _something_, in order to be able to
> skip over (the rest of) the iterations.  It would of course be possible to
> reverse-translate the aux-predicate calls to something that resembles more
> closely the iteration specifiers.
>

When interpreted, no auxiliary predicates are generated and thus no
noise will
occur in the trace. When compiled, no predicate can be traced in B-
Prolog. For example,
assume there are three facts p(1), p(2), p(3) consulted into the
system. Here is the
trace you see for a foreach call in B-Prolog:

| ?- foreach(I in 1..3,p(I))
Call: (0) foreach(_2b0 in 1..3,p(_2b0)) ?
Call: (1) p(1) ?
Exit: (1) p(1) ?
Call: (2) p(2) ?
Exit: (2) p(2) ?
Call: (3) p(3) ?
Exit: (3) p(3) ?
Exit: (0) foreach(_2b0 in 1..3,p(_2b0)) ?

I think this is what users want. You can do the same if you write an
interpreter for ECLiPSe loops.

> In the light of these rather serious issues, what's the big advantage
> that makes them worthwhile?  E.g. is there really a big advantage to
>      ...ac(M,X0)... (X > M^0 -> M^1 = X ; M^1 = M^0)
> with respect to
>      ...fromto(X0,M0,M1,M)... ( X > M0 -> M1 = X ; M1 = M0 )
> that justifies the introduction of a whole new ^-notation?

The ^-notation is used to represent recurrence relations, which have
been used by people to explain
recursion for centuries. To me, it is more intuitive and
understandable than fromto.

Cheers,
Neng-Fa


Kish Shen

unread,
Jun 12, 2009, 1:42:08 PM6/12/09
to

Almost everything is compiled in ECLiPSe, and so the user is almost
always tracing compiled code, so the main issue is how the compiled code
will be traced.

Only meta-called goals are interpreted, and ECLiPSe already has an
`interpreter' for the do loops, and in this case the tracing behaviour
will be similar to your foreach construct.


I think Joachim is suggesting that your transformation of the goals in
the loop body (where the ^-notation is used) is equivalent to the
aux-predicates generated by the transformation in ECLiPSe. In compiled
ECLiPSe, any such goal will already be transformed. Even in an
interpreted context, I assume you need to do the transformation at some
stage, which persumably will be visible to the user unless you supress it?

As Joachim said, you can also supress and/or reverse transform the call
to the aux-predicate and any additional auxillary goals that are
generated. We didn't think the effort was worthwhile. I think one of the
main concern that user had was that they wanted to know which exact
do-loop the aux-predicate showned by the tracer corresponds to. The fact
that the goal shown doesn't look like the original source was not really
a big issue.

>> In the light of these rather serious issues, what's the big advantage
>> that makes them worthwhile? E.g. is there really a big advantage to
>> ...ac(M,X0)... (X > M^0 -> M^1 = X ; M^1 = M^0)
>> with respect to
>> ...fromto(X0,M0,M1,M)... ( X > M0 -> M1 = X ; M1 = M0 )
>> that justifies the introduction of a whole new ^-notation?
>
> The ^-notation is used to represent recurrence relations, which have
> been used by people to explain
> recursion for centuries. To me, it is more intuitive and
> understandable than fromto.
>

To me, a fromto is just another way of writing an accumulator pair, so
it is really as hard or easy to understand as that. It may well be true
that taken in isolation, accumulator pairs are harder to understand than
the ^-notation, but because accumulator pairs is an existing Prolog
programming concep

Ulrich Neumerkel

unread,
Jun 12, 2009, 1:26:11 PM6/12/09
to
Joachim Schimpf <jsch...@users.sourceforge.net> writes:

>afa wrote:
> > First, the syntax is not so good. I don't
>> like the key word "do" in a logic loop construct, especially something
>> like "do true".
>
>A trivial point, but I agree syntax is important. I did consider other
>candidates for the name, in particular holds/2 and :/2. That would have
>made many instances sound/look like mathematical quantifications, e.g.
>
> foreach(X,Xs) holds X > 0
>or
> foreach(X,Xs) : X > 0
>
>The colon wasn't really possible because it is overused already.
>And with holds/2, I would have gotten even more complaints from
>Ulrich for pretending to be logically clean. You could use holds/2
>for a variant of do/2 that doesn't have a cut and can be nondeter-
>ministic, but such a construct should probably not be called a loop.

When I first saw the do in your loops, I thought of the monadic
do in Haskell. There is a certain resemblance indeed - but not
as much as I first thought.

>This also means that you get more of the functionality of maplist/1,2,3,...
>[Incidentally, this whole work was originally motivated by the desire
>for "a better maplist"...]

Could you state what you view as the weakest point of maplist/2,3,4,... ?

Ulrich Neumerkel

unread,
Jun 12, 2009, 1:42:16 PM6/12/09
to
Joachim Schimpf <jsch...@users.sourceforge.net> writes:
>Ulrich Neumerkel wrote:
>> Joachim Schimpf <jsch...@users.sourceforge.net> writes:
>>> Ulrich Neumerkel wrote:
>>>> Jan Wielemaker <j...@nospam.ct.xs4all.nl> writes:
>>>>> Some of these primitives fit poorly in Prolog. ...
>>>> Above loop construct, while very powerful, uses red cuts.
>>> They _can_be_ red. In most cases they aren't. They commit the
>>> termination condition, in the same way the implicit cut in
>>> if-then-else commits the conditional. The cut could be omitted,
>>> but then you'd have to rely on extensive analysis to make sure
>>> that the number of iterations is deterministic.
>>
>> They are always red, if you go for the maximal generalization.
******

>
>Hmmm, maybe the terminology is not clearly defined. I was referring
>to the cuts being green for the intended modes.

We agree here completely. There is this "if" above.

...


> last_keys([], []) :- !. % Green cut for inverse use
> last_keys([L|Ls], [K-L|KLs]) :-
> last(K, L),
> last_keys(Ls, KLs).

The maximal generalization of last_keys/2 is ?- last_keys(Xs,Ys).
And here - only here, the cut now is red.

>We agree. As I said, the situation is like with if-then-else.
>Substitute (List=[] -> true ; List=[_|_]) for (see above).

This could be clean, if there would be an instantiation error
if both arguments are variables.

Ulrich Neumerkel

unread,
Jun 13, 2009, 4:06:08 PM6/13/09
to
Peter Van Weert <Peter.V...@etc.etc.etc> writes:

>Jan Wielemaker wrote:
>> think YAP has the most sensible approach. I wonder why SWI has different
>> priorities (1105 and 1100). Its probably something from lost memories
>I believe the priority of `|' was changed because disjunctions in guards
>of CHR rules parsed incorrectly.

CHR is running also in YAP and SICStus. So they should face the
same problem. What I am interested here in is just uniformity.

Jan Wielemaker

unread,
Jun 14, 2009, 4:22:48 AM6/14/09
to
On 2009-06-12, Peter Van Weert <Peter.V...@etc.etc.etc> wrote:
> Jan Wielemaker wrote:

>> But ... what is the point? Its hard to get these things resolved and
>> resolving them makes very few people outside the ISO group happy. I
>> think YAP has the most sensible approach. I wonder why SWI has different
>> priorities (1105 and 1100). Its probably something from lost memories
>> ...
>>
> I believe the priority of `|' was changed because disjunctions in guards
> of CHR rules parsed incorrectly.

Thanks for reminding me Peter. I checked with git's `blame' facility.
The priority was changed in 2006 with this comment:

* MODIFIED: raised priority of | to 1105 to facilitate CHR. Unlikely
to cause problems. If it does adjust code or use :- op(1100, xfy, (|)).
Jon Sneyers.

So this does indeed raise some issues. Because CHR is the most vulnerable
to the ; vs. | issues I'll leave it with them.

Cheers --- Jan

Ulrich Neumerkel

unread,
Jun 15, 2009, 10:49:56 AM6/15/09
to

Here are some of the consequences.

Omission of solutions:

?- freeze(Xs, (Xs=[];Xs=[a])), ( foreach(_, Xs) do true ).

Nontermination of finite loops:

?- ( for(_,1,2), for(_,1,3) do true ).

Lack of steadfastness w.r.t termination:

?- ( for(I, 1,1), foreach(I, Is) do true ).

terminates, but adding Is = [_,_|_] in front loops.


Problems like these are avoidable.

A.L.

unread,
Jun 15, 2009, 11:50:38 AM6/15/09
to
On Mon, 15 Jun 2009 14:49:56 GMT, ulr...@mips.complang.tuwien.ac.at
(Ulrich Neumerkel) wrote:

>A.L. <alew...@aol.com> writes:
>>On Tue, 09 Jun 2009 13:05:44 GMT, ulr...@mips.complang.tuwien.ac.at
>>(Ulrich Neumerkel) wrote:
>>>Above loop construct, while very powerful, uses red cuts.
>>So what?...
>
>Here are some of the consequences.
>
>Omission of solutions:
>
>?- freeze(Xs, (Xs=[];Xs=[a])), ( foreach(_, Xs) do true ).
>
>Nontermination of finite loops:
>
>?- ( for(_,1,2), for(_,1,3) do true ).

I don't see why. Could you be more specific?...

A.L.

0 new messages