-
- Active Member
- Posts: 36
- Joined: 6 Feb 2003 0:01
Advanced List handling
I've noticed there are some advanced list handling routines available but I haven't been able to find any explanation or example on how to use them.
A very elegant use of these in VP version 7.4 ODBCDemo example, tableForm class is presented although I'm finding it difficult to follow. Specifically the "formatTable" predicate.
Is there a description on how to use list::map, list::fold and list::zip_nd that I can't seem to find?
Regards,
David Snook
A very elegant use of these in VP version 7.4 ODBCDemo example, tableForm class is presented although I'm finding it difficult to follow. Specifically the "formatTable" predicate.
Is there a description on how to use list::map, list::fold and list::zip_nd that I can't seem to find?
Regards,
David Snook
-
- VIP Member
- Posts: 1466
- Joined: 28 Feb 2000 0:01
Well the code in ODBCDemo is not "beginner code".
But in brief:
map applies a function to all elements in a list, returning a new list containing then resulting values:
fold calculates a value from the elements in a list, given a start value:
zip is a function that pairs two lists in to a single list:
zip_nd nondeterministically returns the elements of zipping the lists:
But in brief:
map applies a function to all elements in a list, returning a new list containing then resulting values:
Code: Select all
map([1,2,3], { (X) = X+1} )
= [2,3,4]
Code: Select all
fold(1,2,3], { (Element, Sum) = Element+Sum }, 0)
= fold([1,2], { (Element, Sum) = Element+Sum }, 3+0 )
= fold([1], { (Element, Sum) = Element+Sum }, 2+(3+0) )
= fold([], { (Element, Sum) = Element+Sum }, 1+(2+(3+0)) )
= 1+(2+(3+0))
= 6
Code: Select all
zip([1,2,3], ["a", "b", "c"])
= [tuple(1, "a"), tuple(2, "b"), tuple(3, "c")]
Code: Select all
zip_nd([1,2,3], ["a", "b", "c"])
= getMember_nd(zip([1,2,3], ["a", "b", "c"]))
= getMember_nd( [tuple(1, "a"), tuple(2, "b"), tuple(3, "c")] )
Regards Thomas Linder Puls
PDC
PDC
-
- VIP Member
- Posts: 108
- Joined: 6 Mar 2000 0:01
-
- Active Member
- Posts: 36
- Joined: 6 Feb 2003 0:01
-
- VIP Member
- Posts: 215
- Joined: 24 Apr 2007 12:26
How can I select the value and the index of the smallest element in a list?
Please add some more examples to the new list manipulating commands:
E. g.: How can I select the value and the index of the smallest element in a list?
E. g.: How can I select the value and the index of the smallest element in a list?
TIA, Regards,
Frank Nagy
Frank Nagy
-
- VIP Member
- Posts: 1466
- Joined: 28 Feb 2000 0:01
That kind of list operations are in many respects the opposite of index operations.
The first step in the code below is absolutely not in the spirit of the operations we consider here.
The first step in the code below is absolutely not in the spirit of the operations we consider here.
- L is the input list.
- I varM_integer used to count the indexes.
- IL is a list of indexes ([0, 1, 2, 3, ...]), it is made by mapping a "function" that counts (it is not a function in mathematical sense).
- LIL is the result of zipping the elements together with their indexes [tuple("w", 0), tuple("q", 1), ...]
- In the if-condition I take the first element of the sorted LIL list, which is tha smallest
Code: Select all
clauses
run() :-
L = ["w", "q", "a", "s", "d"],
I = varM_integer::new(-1),
IL = map(L, { (_) = I:value :- I:add(1) }),
LIL = zip(L, IL),
if [tuple(M,MI)|_] = sort(LIL) then
writef("The smallest element is '%' and its index is % (control nth(%, L) = %)\n", M, MI, MI, nth(MI, L))
else
write("The list must be empty")
end if.
Regards Thomas Linder Puls
PDC
PDC
-
- VIP Member
- Posts: 1466
- Joined: 28 Feb 2000 0:01
The formatTable from the ODBC demo program example is an extensive use of these predicates:
If is quite advanced because it works on a two level list. A Table is a list of rows, each of which is a list of strings (i.e. the values in the columns).
The ColumnsLenghts is a similar shaped "table" containing the length of the strings insted of the strings themselves. It is a two level map, because the table is a two level list.
The fold in the if is the most complex operation in the code. If you understand that you understand everything
.
The purpose of the fold is to calculate a list containg the (for each column) largest string length in that column. The fold runs over the rows in Tail and uses Head as initial value. If Tail is empty Head contains the longest lenghts. The function in the fold recieves a row A and an accumulated result B, and it must calculates the next accumulated result.
First it zip the two list together, i.e. the current row and the acumulated result, then it creates a list by selecting the largest of each of these two elements.
Got that
?.
The next step is to create a table of formatted values prefixed with the initial table seperator "|". For each row it zip string values together with the max-width os the corresponding column, and then it format each of these pairs into the desired result.
NewRowsAsStrings is the result of concatenating all the values in each row together with terminating separator. Finally TableAsText is the result of contanating the rows separated by new-lines.
Code: Select all
constants
separator = "|".
predicates
formatTable : (string** Table) -> string TableAsText.
clauses
formatTable(RowsList) = TableAsText :-
ColumnsLenths = list::map(RowsList, {(Row) = list::map(Row, string::length)}),
if [Head | Tail] = ColumnsLenths then
MaxLengths = list::fold(Tail, {(A, B) = [math::max(Aj, Bj) || tuple(Aj, Bj) = list::zip_nd(A, B)]}, Head),
NewRows = list::map(RowsList,
{(Columns) = [string::format("% % ", separator, Col) ||
tuple(C, Length) = list::zip_nd(Columns, MaxLengths),
SpaceAc = Length - string::length(C),
Col = string::concat(C, string::create(SpaceAc, " "))] }),
NewRowsAsStrings = list::map(NewRows, {(ColList) = string::concat(string::concatList(ColList), separator)}),
TableAsText = string::concatWithDelimiter(NewRowsAsStrings, "\n")
else
TableAsText = ""
end if.
The ColumnsLenghts is a similar shaped "table" containing the length of the strings insted of the strings themselves. It is a two level map, because the table is a two level list.
The fold in the if is the most complex operation in the code. If you understand that you understand everything

The purpose of the fold is to calculate a list containg the (for each column) largest string length in that column. The fold runs over the rows in Tail and uses Head as initial value. If Tail is empty Head contains the longest lenghts. The function in the fold recieves a row A and an accumulated result B, and it must calculates the next accumulated result.
First it zip the two list together, i.e. the current row and the acumulated result, then it creates a list by selecting the largest of each of these two elements.
Got that

The next step is to create a table of formatted values prefixed with the initial table seperator "|". For each row it zip string values together with the max-width os the corresponding column, and then it format each of these pairs into the desired result.
NewRowsAsStrings is the result of concatenating all the values in each row together with terminating separator. Finally TableAsText is the result of contanating the rows separated by new-lines.
Last edited by Thomas Linder Puls on 5 Dec 2012 10:25, edited 1 time in total.
Regards Thomas Linder Puls
PDC
PDC
-
- VIP Member
- Posts: 215
- Joined: 24 Apr 2007 12:26
Other solution of minimum and its index
Thomas,
you were overzealous.
The list::sort order the whole list which is expensive in case of a long list.
I have another idea:
calculates the minimal value.
The next step is the getting of the index:.
Can I put an within the {...} of the above code?
you were overzealous.
The list::sort order the whole list which is expensive in case of a long list.
I have another idea:
Code: Select all
MinValue=fold(List, { (Element, Min) = math::min(Element,Min)}, upperBound(<domain of Element>)
The next step is the getting of the index:
Code: Select all
MinsIndex=list::trygetIndex(MinValue,LiIst)
Can I put an
Code: Select all
if <do something> endif
TIA, Regards,
Frank Nagy
Frank Nagy
-
- VIP Member
- Posts: 1466
- Joined: 28 Feb 2000 0:01
-
- VIP Member
- Posts: 215
- Joined: 24 Apr 2007 12:26
Are findall and forall deprecated?
Are the old (defined 25 years age on Turbo Prolog) findall and the relative new list::forall predicates deprecated?
TIA, Regards,
Frank Nagy
Frank Nagy
-
- VIP Member
- Posts: 1466
- Joined: 28 Feb 2000 0:01
findall is a list comprehension, and we reccomend using the list comprehension. So in that respect I consider findall deprecated.
But forall is not deprecated. There are a lot of different ways write a certain list routine, and sometimes one method is prefarable to another, but at other times it may be different.
But forall is not deprecated. There are a lot of different ways write a certain list routine, and sometimes one method is prefarable to another, but at other times it may be different.
Regards Thomas Linder Puls
PDC
PDC
-
- Active Member
- Posts: 47
- Joined: 19 Sep 2011 8:54
Is there any way we can terminate the forAll loop in middle of the processing ?
Ex :
When the Head is "D", it should end the loop and it should not proceed further to check "E", "F" etc..
How can we do this on the forAll loop. ??
Ex:
How to do the above on forAll loop ?
Ex :
Code: Select all
class predicates
testForAllLoop : ().
clauses
testForAllLoop():-
MyList = ["A", "B", "C", "D", "E", "F", "G"],
list::forAll(MyList, {(Head):-
if Head = "D" then
! %Need to end the loop here - please suggest me..
end if
}).
How can we do this on the forAll loop. ??
Ex:
Code: Select all
class predicates
loopThrough : (string, string*).
clauses
loopThrough(_,[]):- !.
loopThrough(Head, [Head|_]):- !.
loopThrough(Head, [_|Rest]):-
loopThrough(Head, Rest).
-
- VIP Member
- Posts: 1466
- Joined: 28 Feb 2000 0:01
-
- Active Member
- Posts: 47
- Joined: 19 Sep 2011 8:54
I agree with your point, Mr. Thomas Linder Puls..Why use a predicate against its obvious intention?
I felt like code minimization - Instead of using too many predicates for doing small Job.. I could use "forAll/.." predicate to loop through..
When we have a option to break through - foreach loop : why don't we bring option to break "forAll/.." loop..
If you bring a option to setup a boundary condition inside forAll/.. loop that will be great..
Sure, I'll follow this Standard, Mr. Thomas Linder Puls.I suggest that you don't use forAll when you don't want to do it for all elements.

-
- VIP Member
- Posts: 458
- Joined: 5 Nov 2000 0:01
Re:
Two little predicates and your job is done.
%-- a member is "before" the Chop
%-- as long as the Tail of the list contains the Chop string
before_nd( Chop, [S|T], S ):- member( Chop, T ).
before_nd( S, [_|T], BF ):- before_nd( S, T, BF ).
member( S, [S|_] ):- !.
member( S, [_|T] ):- member(S,T).
QED:
%-- a member is "before" the Chop
%-- as long as the Tail of the list contains the Chop string
before_nd( Chop, [S|T], S ):- member( Chop, T ).
before_nd( S, [_|T], BF ):- before_nd( S, T, BF ).
member( S, [S|_] ):- !.
member( S, [_|T] ):- member(S,T).
QED:
Code: Select all
PREDICATES
testForAllLoop
member( STRING, SLIST ) -(i,i)
nondeterm before_nd( STRING, SLIST, STRING ) -(i,i,o)
CLAUSES
before_nd( Chop, [S|T], S ):- member( Chop, T ).
before_nd( S, [_|T], BF ):- before_nd( S, T, BF ).
member( S, [S|_] ):- !.
member( S, [_|T] ):- member(S,T).
testForAllLoop:-
MyList = ["A","B","C","X","D","E","F"],
StopStr = "X",
findall( S, before_nd( StopStr, MyList, S ), SS ),
write( "Front list: ", SS, "\n" ),
fail.
testForAllLoop:-
MyList = ["A","B","C","X","D","E","F"],
StopStr = "X",
before_nd(StopStr,MyList,S), % operate on S and backtrack
%-- do something here:
write( "Backtrack result: ", S, "\n" ),
fail.
testForAllLoop:-
MyList = ["A","B","C","X","D","E","F"],
StopStr = "Q",
before_nd(StopStr,MyList,S), % FAIL if StopStr not in MyList
%-- do something here:
write( "Backtrack result: ", S, "\n" ),
fail.
testForAllLoop:-
MyList = ["X"],
StopStr = "X",
before_nd(StopStr,MyList,S), % FAIL if no strings before StopStr
%-- do something here:
write( "Backtrack result: ", S, "\n" ),
fail.
testForAllLoop.