[net.lang.prolog] PROLOG Digest V4 #5

PROLOG-REQUEST@SU-SCORE.ARPA (Chuck Restivo, The Moderator) (01/24/86)

PROLOG Digest            Monday, 27 Jan 1986        Volume 4 : Issue 5

Today's Topics:
        Implementation - Syntactic Sugar & Coding Algorithms,
      LP Philosophy - What is the expressive ability of Prolog?
----------------------------------------------------------------------

Date: 20 Jan 86 16:59:46-EST (Mon)
From: Zerksis D. Umrigar <Zerksis%sutcase.bitnet@wiscvm.arpa>
Subject: More syntactic sugar for Prolog.

One can drastically reduce the use of cuts in Prolog programs
by the use of  if-then-else  control constructs. However, I feel
that the syntax of 'if P then Q else R' in most Prolog implement
-ations (P-> Q ;  R)  leaves much  to  be  desired.  By  introducing
a declaration similar to op, it should be possible to permit non
-iterative control constructs similar to those  found  in  most
procedural  languages, while still retaining the syntax of Prolog
"clauses" as terms.

Basically, the idea is that one should allow general  parentheses,
with general  punctuation.  Hence  one  can think of 'if' as left
parenthesis with say 'end_if' as the closing parenthesis. 'then'
and 'else' would be general  punctuation  marks.  The precedence of
any term enclosed within general parentheses would be identical to
that enclosed within  '('  and ')'  (0  for  DEC-10  Prolog).  The
declaration could be something like :-paren([if,then,else,end_if]).

By allowing suitable  meta-characters  in  the  declaration,  one
could specify  optional  punctuation,  or  punctuation  characters
which  are repeated 0 or more times. This would make possible the
use  of  if-then and  case control constructs. (The semantics of
the case statement would be  to  commit  to  the  first  alternative
whose   guard   is   solved successfully).  Another  useful
construct would be something similar to case, which would allow
backtracking over the "guards" - (equivalent  to cut-free disjunction
in regular Prolog).

If the implementation looks at the control constructs at  the
top-level of  a  "clause",  it should be possible for it to
automatically generate indexing information to obtain rapid
access to the  chosen  alternative. This   should  make  it
possible  to  write  efficient  single-"clause" procedures.

Hopefully, this sugared syntax should be easier to read  and
comprehend than regular Prolog syntax.

Any comments?

------------------------------

Date: 22 Jan 1986 00:04-CST
From: Kale@uiucdcsb.CS.UIUC.EDU
Subject: Coding an interesting algorithm in Prolog

Recently, I was reading an algorithm (fairly complex, it seemed)
for finding the median of a set of numbers in linear time. At the
back of my mind were arguments I recently had regarding the
suitability of Prolog for coding complex algorithms.  So I decided
to code it.  I was pleasnatly surprised at the simplicity of code
and the ease of coding.

Here is the code:

/* Given a list of length N and a number K, `select' selects an
   element, E, of the list such that there are exactly K-1 elemets
   less than E.   This can be used for finding the median by calling
   it with K = length/2.
   The algorithm requires 28*N comparisons. */

select(L,K,V) :-  length(L,N), N < 28, !, sort(L,L1), nth_member(L1,K,V).
                                                      
select(L,K,V) :-
        choose(L,M),  /* Choose a member of L that is `close' to
        the median */

        partition(L,M,L1,Length1,L2),
        ((K =< Length1, select(L1,K,V)) ;
         (K2 is K - Length1, select(L2,K2,V))).

choose(L,M) :- medians(L,S,Length_S), N is (Length_S // 2)+1, select(S,N,M).
                                                              

medians([X1,X2,X3,X4,X5,X6,X7|Rest],[Y|New],Length1) :- !,
        sort([X1,X2,X3,X4,X5,X6,X7],[_,_,_,Y,_,_,_]),
        medians(Rest,New,Length), Length1 is Length+1.
medians(L,[],0).

partition([],M,[],0,[]).
partition([First|Rest],M,[First|L1],Length1,L2) :-
        First < M, !,
        partition(Rest,M,L1,Length,L2),
        Length1 is Length + 1.
partition([First|Rest],M,L1,Length1,[First|L2]) :-
        partition(Rest,M,L1,Length1,L2).

nth_member([F|R],1,F).
nth_member([F|R],N,M) :- N > 1, N1 is N-1, nth_member(R,N1,M).

/* coded for CProlog */

The algorithm is taken from the book `combinatorial algorithms'
by Reingold, Deo, and Nievergelt.

I used the system sort here, which is ok ONLY IF the original
list does not have duplicates. The system sort eats up the
duplicates. Write your own (bubble) sort if you have duplicates.
The first clause can be taken to provide the definition of the
problem, (without the `length < 28' check). For linearity, all
that  you have to ensure is that the first clause requires
(< 28*n) comparisons.

Proof of Linearity: The `choose' predicate finds a member that
is close to the median in the sense that there are at least
(n*2/7) on either side of it. Thus the worst case recursive-call
will be on a list of length 5n/7, taking 28*5n/7 =20n comparisons
by inductive hypothesis.  `choose' itself takes 3n comparisons to
sort the sublists of length 7 each, and 4n to find the `median of
the medians' recursively (28*n/7).

`partition' takes n more comps. , so the total is: 20n+3n+4n+n=28n!
The first clause provides the BASIS for the inductive proof.

-- Kale

p.s. Do people out there have examples of complex data structures
being coded in Prolog? Some of my concerns are algorithms for
graph traversals that need to repeatedly update values at nodes,
connectionist algorithms etc.

------------------------------

Date: Mon 20 Jan 86 11:31:04-PST
From: Fernando Pereira <PEREIRA@SRI-CANDIDE.ARPA>
Subject: Expressive ability

The expressive power of machine languages it the power of
being able to instruct a machine to do any elementary step
(machine instruction) that the machine has been designed to
do. That kind of expressive power is thus irrevocably tied
to a particular machine architecture, so let's call it
``machine power''.

Like many other computer scientists, advocates of logic
programming understand the advantages of relinquishing machine
power in favor of ``abstraction power'': the ability to express
abstract relationships and processes without having to delve
into  the peculiarities of the implementation of that expression
on a particular machine.

The discipline needed to keep abstractions alive in a language
with substantial machine power (such as Lisp) seems beyond the
grasp of most programmers, to judge by their products. Learning
to use a language with superior abstraction power but little
machine power takes time and also requires discipline, but pays
off in better products: maintainable, reusable.

The tremendous growth and success of modern mathematics depended
in no small measure on the acquisition by mathematicians of
increasingly powerful abstraction tools. The laborious combinato
-rial methods of 19th century algebra (the mathematical counter
-part of machine power), are today of only historical interest,
and no  one (well, almost no one...) would blame a present-day
mathematician for not being able to work in those terms.

Our inability to build reliable software products is not due to
lack of machine power in our tools (we have had plenty ot that...)
but to our inability to predict the interactions between components
for which there are no good abstract specifications and implementa
-tions. The practice of Lisp programming shows this clearly. Current
logic programming tools are somewhat better, but clearly not good
enough, particularly with respect to modularity.

We should not let criticisms of logic programming from the point of
view of a programming practice discredited by the unreliability of
its products manuever us into wasting our effort trying to increase
the machine power of logic programming tools rather than building on
logic programming's strength, abstraction power.

-- Fernando Pereira

------------------------------

End of PROLOG Digest
********************

PROLOG-REQUEST@SU-SCORE.ARPA (Chuck Restivo, The Moderator) (01/27/86)

PROLOG Digest            Tuesday, 28 Jan 1986       Volume 4 : Issue 5

Today's Topics:
        Implementation - Syntactic Sugar & Coding Algorithms,
       LP Philosophy - What is the expressive power of Prolog?
----------------------------------------------------------------------

Date: 20 Jan 86 16:59:46-EST (Mon)
From: Zerksis D. Umrigar <Zerksis%sutcase.bitnet@wiscvm.arpa>
Subject: More syntactic sugar for Prolog.

One can drastically reduce the use of cuts in Prolog programs
by the use of  if-then-else  control constructs. However, I feel
that the syntax of 'if P then Q else R' in most Prolog implement
-ations (P-> Q ;  R)  leaves much  to  be  desired.  By  introducing
a declaration similar to op, it should be possible to permit non
-iterative control constructs similar to those  found  in  most
procedural  languages, while still retaining the syntax of Prolog
"clauses" as terms.

Basically, the idea is that one should allow general  parentheses,
with general  punctuation.  Hence  one  can think of 'if' as left
parenthesis with say 'end_if' as the closing parenthesis. 'then'
and 'else' would be general  punctuation  marks.  The precedence of
any term enclosed within general parentheses would be identical to
that enclosed within  '('  and ')'  (0  for  DEC-10  Prolog).  The
declaration could be something like :-paren([if,then,else,end_if]).

By allowing suitable  meta-characters  in  the  declaration,  one
could specify  optional  punctuation,  or  punctuation  characters
which  are repeated 0 or more times. This would make possible the
use  of  if-then and  case control constructs. (The semantics of
the case statement would be  to  commit  to  the  first  alternative
whose   guard   is   solved successfully).  Another  useful
construct would be something similar to case, which would allow
backtracking over the "guards" - (equivalent  to cut-free disjunction
in regular Prolog).

If the implementation looks at the control constructs at  the
top-level of  a  "clause",  it should be possible for it to
automatically generate indexing information to obtain rapid
access to the  chosen  alternative. This   should  make  it
possible  to  write  efficient  single-"clause" procedures.

Hopefully, this sugared syntax should be easier to read  and
comprehend than regular Prolog syntax.

Any comments?

------------------------------

Date: 22 Jan 1986 00:04-CST
From: Kale@uiucdcsb.CS.UIUC.EDU
Subject: Coding an interesting algorithm in Prolog

Recently, I was reading an algorithm (fairly complex, it seemed)
for finding the median of a set of numbers in linear time. At the
back of my mind were arguments I recently had regarding the
suitability of Prolog for coding complex algorithms.  So I decided
to code it.  I was pleasnatly surprised at the simplicity of code
and the ease of coding.

Here is the code:

/* Given a list of length N and a number K, `select' selects an
   element, E, of the list such that there are exactly K-1 elemets
   less than E.   This can be used for finding the median by calling
   it with K = length/2.
   The algorithm requires 28*N comparisons. */

select(L,K,V) :-  length(L,N), N < 28, !, sort(L,L1), nth_member
                                                      (L1,K,V).
select(L,K,V) :-
        choose(L,M),  /* Choose a member of L that is `close' to
        the median */

        partition(L,M,L1,Length1,L2),
        ((K =< Length1, select(L1,K,V)) ;
         (K2 is K - Length1, select(L2,K2,V))).

choose(L,M) :- medians(L,S,Length_S), N is (Length_S // 2)+1, select
                                                              (S,N,M).

medians([X1,X2,X3,X4,X5,X6,X7|Rest],[Y|New],Length1) :- !,
        sort([X1,X2,X3,X4,X5,X6,X7],[_,_,_,Y,_,_,_]),
        medians(Rest,New,Length), Length1 is Length+1.
medians(L,[],0).

partition([],M,[],0,[]).
partition([First|Rest],M,[First|L1],Length1,L2) :-
        First < M, !,
        partition(Rest,M,L1,Length,L2),
        Length1 is Length + 1.
partition([First|Rest],M,L1,Length1,[First|L2]) :-
        partition(Rest,M,L1,Length1,L2).

nth_member([F|R],1,F).
nth_member([F|R],N,M) :- N > 1, N1 is N-1, nth_member(R,N1,M).

/* coded for CProlog */

The algorithm is taken from the book `combinatorial algorithms'
by Reingold, Deo, and Nievergelt.

I used the system sort here, which is ok ONLY IF the original
list does not have duplicates. The system sort eats up the
duplicates. Write your own (bubble) sort if you have duplicates.
The first clause can be taken to provide the definition of the
problem, (without the `length < 28' check). For linearity, all
that  you have to ensure is that the first clause requires
(< 28*n) comparisons.

Proof of Linearity: The `choose' predicate finds a member that
is close to the median in the sense that there are at least
(n*2/7) on either side of it. Thus the worst case recursive-call
will be on a list of length 5n/7, taking 28*5n/7 =20n comparisons
by inductive hypothesis.  `choose' itself takes 3n comparisons to
sort the sublists of length 7 each, and 4n to find the `median of
the medians' recursively (28*n/7).

`partition' takes n more comps. , so the total is: 20n+3n+4n+n=28n!
The first clause provides the BASIS for the inductive proof.

-- Kale

p.s. Do people out there have examples of complex data structures
being coded in Prolog? Some of my concerns are algorithms for
graph traversals that need to repeatedly update values at nodes,
connectionist algorithms etc.

------------------------------

Date: Mon 20 Jan 86 11:31:04-PST
From: Fernando Pereira <PEREIRA@SRI-CANDIDE.ARPA>
Subject: Expressive ability

The expressive power of machine languages it the power of
being able to instruct a machine to do any elementary step
(machine instruction) that the machine has been designed to
do. That kind of expressive power is thus irrevocably tied
to a particular machine architecture, so let's call it
``machine power''.

Like many other computer scientists, advocates of logic
programming understand the advantages of relinquishing machine
power in favor of ``abstraction power'': the ability to express
abstract relationships and processes without having to delve
into  the peculiarities of the implementation of that expression
on a particular machine.

The discipline needed to keep abstractions alive in a language
with substantial machine power (such as Lisp) seems beyond the
grasp of most programmers, to judge by their products. Learning
to use a language with superior abstraction power but little
machine power takes time and also requires discipline, but pays
off in better products: maintainable, reusable.

The tremendous growth and success of modern mathematics depended
in no small measure on the acquisition by mathematicians of
increasingly powerful abstraction tools. The laborious combinato
-rial methods of 19th century algebra (the mathematical counter
-part of machine power), are today of only historical interest,
and no  one (well, almost no one...) would blame a present-day
mathematician for not being able to work in those terms.

Our inability to build reliable software products is not due to
lack of machine power in our tools (we have had plenty ot that...)
but to our inability to predict the interactions between components
for which there are no good abstract specifications and implementa
-tions. The practice of Lisp programming shows this clearly. Current
logic programming tools are somewhat better, but clearly not good
enough, particularly with respect to modularity.

We should not let criticisms of logic programming from the point of
view of a programming practice discredited by the unreliability of
its products manuever us into wasting our effort trying to increase
the machine power of logic programming tools rather than building on
logic programming's strength, abstraction power.

-- Fernando Pereira

------------------------------

End of PROLOG Digest
********************