How do collector functions work in Scheme? - scheme

I am having trouble understanding the use of collector functions in Scheme. I am using the book "The Little Schemer" (by Daniel P. Friedman and Matthias Felleisen). A comprehensive example with some explanation would help me massively. An example of a function using a collector function is the following snippet:
(define identity
(lambda (l col)
(cond
((null? l) (col '()))
(else (identity
(cdr l)
(lambda (newl)
(col (cons (car l) newl))))))))
... with an example call being (identity '(a b c) self) and the self-function being (define self (lambda (x) x)). The identity function returns the given list l, so the output of the given call would be (a b c). The exact language used is the R5RS Legacy-language.

Given how those "collector" functions are defined in the identity definition, calling
(identity xs col)
for any list xs and some "collector" function col, is equivalent to calling
(col xs)
so the same list will be "returned" i.e. passed to its argument "collector" / continuation function col. That explains its name, identity, then.
For comparison, a reverse could be coded as
(define reverse ; to be called as e.g. (reverse l display)
(lambda (l col)
(cond
((null? l) (col '())) ; a reversed empty list is empty
(else (reverse (cdr l) ; a reversed (cdr l) is newl --
(lambda (newl) ; what shall I do with it when it's ready?
(col ; append (car l) at its end and let col
(append newl ; deal with it!
(list (car l))))))))))
This style of programming is known as continuation-passing style: each function is passed a "continuation" that is assumed that it will be passed the result of the rest of computation, so that the original continuation / collector function will be passed the final result eventually. Each collector's argument represents the future "result" it will receive, and the collector function itself then specifies how it is to be handled then.
Don't get confused by the terminology: these functions are not "continuations" captured by the call/cc function, they are normal Scheme functions, representing "what's to be done next".
The definition can be read as
identity :
to transform a list xs
with a collector function col,
is
| to call (col xs) , if xs is empty, or
| to transform (cdr xs)
with a new collector function col2
such that
(col2 r) = (col (cons (car xs) r)) , otherwise.
(or we can write this in a pseudocode, as)
(identity list col) =
| empty? list -> (col list)
| match? list (x . xs) -> (identity xs col2)
where
(col2 r) = (col (cons x r))
col2 handles its argument r by passing (cons x r) to the previous handler col. This means r is transformed into (cons x r), but instead of being returned as a value, it is fed into col for further processing. Thus we "return" the new value (cons x r) by passing it to the previous "collector".
A sample call, as an illustration:
(identity (list 1 2 3) display)
= (identity (list 2 3) k1)
; k1 = (lambda (r1) (display (cons 1 r1))) = display ° {cons 1}
= (identity (list 3) k2)
; k2 = (lambda (r2) (k1 (cons 2 r2))) = k1 ° {cons 2}
= (identity (list ) k3)
; k3 = (lambda (r3) (k2 (cons 3 r3))) = k2 ° {cons 3}
= (k3 '()) ; (((display ° {cons 1}) ° {cons 2}) ° {cons 3}) []
= (k2 (cons 3 '())) ; ((display ° {cons 1}) ° {cons 2}) [3]
= (k1 (cons 2 (list 3))) ; (display ° {cons 1}) [2,3]
= (display (cons 1 (list 2 3))) ; display [1,2,3]
= (display (list 1 2 3))
update: in a pattern-matching pseudocode I've been fond of using as of late, we could write
identity [] col = col []
identity [a, ...d] col = identity d ( newl => col [a, ...newl] )
and
reverse [] col = col []
reverse [a, ...d] col = reverse d ( newl => col [...newl, a] )
which hopefully is so much visually apparent that it almost needs no explanation!

I'm adding the second answer in the hopes it can clarify the remaining doubts in case you have any (as the lack of the "accepted" mark would indicate).
In the voice of Gerald J. Sussman, as heard/seen in the SICP lectures of which the videos are available here and there on the internet tubes, we can read it as we are writing it,
(define identity
"identity" is defined to be
(lambda
that function which, when given
(l col)
two arguments, l and col, will
(cond
((null? l)
-- in case (null? l) is true --
OK, this means l is a list, NB
(col '()))
return the value of the expression (col '())
OK, this now means col is a function, expecting of one argument, as one possibility an empty list,
(else (identity (cdr l)
or else it will make a tail recursive call with the updated values, one being (cdr l),
(lambda (newl)
(col (cons (car l) newl)))))))
and the other a newly constructed function, such that when it will be called with its argument newl (a list, just as was expected of col -- because it appears in the same role, it must follow the same conventions), will in turn call the function col with the non-empty list resulting from prefixing (car l) to the list newl.
Thus this function, identity, follows the equations
( identity (cons (car l) (cdr l)) col )
==
( identity (cdr l) (lambda (newl) (col (cons (car l) newl))) )
and
( identity '() col )
==
( col '() )
describing an iterative process, the one which turns the function call
(identity [a, b, c, ..., n] col )
into the call
(col
(cons a (cons b (cons c ... (cons n '()) ... ))))
recreating the same exact list anew, before feeding it as an argument to the function col it has been supplied with.

Related

How do I get this code in Racket to return only the non-repeating items?

The code works like this, I pass several lists and it returns me all lists in just one. What I want it to do is that after joining the elements in a list, it removes the repeating elements. To be clearer:
The code is working like this:
> (koo '(p x k c l) '(l x y c) '(x k))
'(p x k c l l x y c x k)
I want him to come back to me like this:
> (koo '(p x k c l) '(l x y c) '(x k))
'(p y )
Here the code:
(define (koo . c)
(if (null? c)
empty
(concatenate1 (first c)
(apply xor* (rest c)))))
(define (concatenate1 l1 l2)
(if (null? l1)
l2
(cons (first l1) (concatenate1 (rest l1) l2))))
A not very efficient version using just basic racket functions:
(define (unique-elements lst)
(let ((dup (check-duplicates lst)))
(if dup
(unique-elements (remove* (list dup) lst))
lst)))
(define (xor* . lol) (unique-elements (append* lol)))
Looks for the first duplicate element, and if any, removes all instances of that element from the list, and repeat until there are no duplicates.
Documentation for check-duplicates.
Documentation for remove*
Documentation for append*

adding element to a list

I am trying to implement a procedure in Scheme that will add an element x at position i to an existing list. This is what I came up with:
(define empty-list '())
(define (add i x L)
(cond ((null? L) (set! L (list x)))
((= i 0)(set! L (cons x L)))
(else (set! L (cons (car L)
(add (- i 1) x (cdr L))))
)))
(add 0 1 empty-list) -> returns ()
(add 1 2 empty-list) -> returns ()
(add 2 3 empty-list) -> returns ()
The code doesn't update the existing list. However, if I just run
(set! empty-list (list 1)) or
(set! empty-list (cons 2 empty-list)) it works fine.
I am struggling to understand what I am doing wrong.
When using set! you are not changing the actual value but you assign the most specific binding with a new value. In JavaScript it works the same:
function add (arr, element) {
arr = arr.concatenate([element]);
return arr;
}
const test = [1, 2, 3];
add(test, 4); // => [1, 2, 3, 4]
test; // => [1, 2, 3]
These kind of procedures in Scheme are usually not mutating. If you remove set! with the value it will return the correct value:
(define (add i x L)
(cond
((null? L) (list x)) ; might not be at correct position
((= i 0) (cons x L))
(else (cons (car L) (add (- i 1) x (cdr L))))))
(add 1 'b '(a c)) ; ==> (a b c)
In Scheme, like many functional languages, we update the states by calling the recurring function with updated arguments.
(define (add i x l)
;; handle base cases outside of recursion, such as
;; if the starting list is empty, `i` is disregarded etc.
(cond [(null? l) (cons x l)]
[(null? (cdr l))
(if (<= i 0)
(cons x l)
(append l (list x)))]
[else
(let recur ([start l] [index 0])
;; base case
(if (= index i)
(cons x start)
;; this is how states are updated
(cons (car start) (recur (cdr start) (+ index 1)))))]))
;; > (add 3 'newguy '(mary peter nguyen joo kim))
;; '(mary peter nguyen newguy joo kim)

Prolog translation of Lisp's tail-recursion

I have a question that is a followup to a previous topic,
Should I avoid tail recursion in Prolog and in general?
In the above linked article , user false
provided this code example and this explanation ...
Back in the 1970s, the major AI language was LISP. And the
corresponding definition would have been ...
(defun addone (xs)
(cond ((null xs) nil)
(t (cons (+ 1 (car xs))
(addone (cdr xs))))))
... which is not directly tail-recursive: The reason is the cons:
In implementations of that time, its arguments were evaluated first,
only then, the cons could be executed. So rewriting this as you have
indicated (and reversing the resulting list) was a possible
optimization technique.
In Prolog, however, you can create the cons prior to knowing the
actual values, thanks to logic variables. So many programs that were
not tail-recursive in LISP, translated to tail-recursive programs in
Prolog.
The repercussions of this can still be found in many Prolog
textbooks.
My question is : what is a good Prolog translation of the above
LISP code ?
EDIT: added the example of the lisp code in action and the
lisp documentation describing the various lisp functions .
example of addone in action
1 > (addone '(1 2 3))
(2 3 4)
2 > (addone '('()))
> Error: The value 'NIL is not of the expected type NUMBER.
> While executing: CCL::+-2, in process listener(1).
> Type :POP to abort, :R for a list of available restarts.
> Type :? for other options.
3 > (addone '(a b c))
> Error: The value A is not of the expected type NUMBER.
> While executing: CCL::+-2, in process listener(1).
> Type :POP to abort, :R for a list of available restarts.
> Type :? for other options.
3 > ^C
documentation of lisp features
cons object-1 object-2 => cons
Creates a fresh cons ,
the car of which is object-1 ,
and the cdr of which is object-2 .
Examples
(cons 1 2) => (1 . 2)
(cons 1 nil) => (1)
(cons nil 2) => (NIL . 2)
(cons nil nil) => (NIL)
(cons 1 (cons 2 (cons 3 (cons 4 nil)))) => (1 2 3 4)
(cons 'a 'b) => (A . B)
(cons 'a (cons 'b (cons 'c '()))) => (A B C)
(cons 'a '(b c d)) => (A B C D)
(car x) => object
If x is a cons ,
car returns the car of that cons .
If x is nil ,
car returns nil .
(cdr x) => object
If x is a cons ,
cdr returns the cdr of that cons .
If x is nil ,
cdr returns nil
.
cond {clause}* => result*
clause::= (test-form form*)
Test-forms are evaluated one at a time in the order in which they
are given in the argument list until a test-form is found that
evaluates to true .
If there are no forms in that clause, the primary value of the
test-form [ed: the first value of the test-form , or nil if there
are no values] is returned by the cond form. Otherwise, the forms
associated with this test-form are evaluated in order, left to
right, as an implicit progn, and the values returned by the last
form are returned by the cond form.
Once one test-form has yielded true, no additional test-forms are
evaluated. If no test-form yields true, nil is returned
See
http://www.lispworks.com/documentation/HyperSpec/Body/m_cond.htm#cond
for more information .
defun function-name lambda-list form* => function-name
See
http://www.lispworks.com/documentation/HyperSpec/Body/m_defun.htm#defun
for more information .
t => T
t => T
(eq t 't) => T
(case 'b (a 1) (t 2)) => 2
Here's a rendition in Prolog of the given Lisp algorithm. Note that Lisp is functional and a Lisp function can return values. This isn't the case in Prolog, so you need two arguments.
A direct implementation, which is not relational, would be:
addone([], []).
addone([H|T], [H1|T1]) :-
H1 is H + 1,
addone(T, T1).
Note that the [H1|T1] argument in the head of the second predicate clause corresponds to (cons H1 T1) in Lisp.
This can also be done using maplist, which steps a little bit away from the original Lisp implementation, but Lisp does have list mapping functions which could be used to create a Lisp implementation that would look more like this:
addone_element(X, X1) :- X1 is X + 1.
addone(List, List1) :- maplist(addone_element, List, List1).
In Prolog this can be made more relational using CLP(FD) which is useful for reasoning over integers:
:- use_module(library(clpfd)).
addone([], []).
addone([H|T], [H1|T1]) :-
H1 #= H + 1,
addone(T, T1).
And the maplist version:
addone_element(X, X1) :- X1 #= X + 1.
addone(List, List1) :- maplist(addone_element, List, List1).
A direct translation:
(defun addone (xs)
(cond ((null xs) nil)
(t (cons (+ 1 (car xs))
(addone (cdr xs))))))
is
addone( XS, RESULT) :-
( XS = [], % null XS ? then:
RESULT = [] %
;
XS = [CAR | CDR], % else:
R is 1 + CAR, % calculate the two
addone( CDR, S) % fields % almost TR,
RESULT = [R | S], % and cons them up % save for this cons
).
But, transformed,
(defun addone (xs)
(let ((result))
(cond ((null xs) (setf result nil))
(t (setf result (cons (+ 1 (car xs))
(addone (cdr xs))))))
result))
=
(defun addone (xs)
(let ((result))
(cond ((null xs) (setf result nil))
(t (setf result (list nil))
(setf (car result) (+ 1 (car xs)))
(setf (cdr result) (addone (cdr xs)))))
result))
=
(defun addone (xs &optional (result (list nil))) ; head sentinel
(cond ((null xs))
(t (setf (cdr result) (list nil))
(setf (cadr result) (+ 1 (car xs)))
(addone (cdr xs) (cdr result)))) ; almost TR
(cdr result)) ; returned but not used
=
(defun addone (xs &aux (result (list nil)))
(labels ((addone (xs result)
(cond ((null xs))
(t (setf (cdr result) (list nil))
(setf (cadr result) (+ 1 (car xs)))
(addone (cdr xs) (cdr result)))))) ; fully TR
(addone xs result))
(cdr result))
it is, fully tail recursive,
addone( XS, RESULT) :-
( XS = [],
RESULT = []
;
XS = [CAR | CDR],
RESULT = [R | S], % cons two empty places, and
R is 1 + CAR, % fill'em
addone( CDR, S) % up % fully TR
).
Boxing / head sentinel is used so we can have settable pointers in Common Lisp, but in Prolog this isn't needed -- Prolog's logical variables are directly settable (once), named pointers.
This is also the reason why Prolog's transformation is so much smaller and easier than Lisp's. All it took was moving one line of code up a notch or two (and it could've been one just the same).

Scheme set made from parts of set

Hi i'm trying to define a function which should make a set from the parts of that set.
Should be defined like: P(A) = P(A-{x}) U { {x} U B} for all B that belongs to P(A-{X}) where X belongs to A.
A test would be:
(parts '(a b c))
=> ((a b c) (a b) (a c) (a) (b c) (b) (c)())
I've been trying with this one:
(define (mapc f x l)
(if (null? l)
l
(cons (f x (car l)) (mapc f x (cdr l)))))
Maybe something like this? (untested)
(define (power-set A)
(cond
[(null? A) '()] ; the power set of an empty set it empty
[else (append (map (lambda (S) (cons x S)) ; sets with x
(power-set (cdr A)))
(power-set (cdr A)) ; sets without x
]))
This is essentially 'combinations' function (https://docs.racket-lang.org/reference/pairs.html?q=combinations#%28def._%28%28lib._racket%2Flist..rkt%29._combinations%29%29).
Following short code in Racket (a Scheme derivative) gets all combinations or parts:
(define (myCombinations L)
(define ol (list L)) ; Define outlist and add full list as one combination;
(let loop ((L L)) ; Recursive loop where elements are removed one by one..
(for ((i L)) ; ..to create progressively smaller combinations;
(define K (remove i L))
(set! ol (cons K ol)) ; Add new combination to outlist;
(loop K)))
(remove-duplicates ol))
Testing:
(myCombinations '(a b c))
Output:
'(() (a) (b) (a b) (c) (a c) (b c) (a b c))

filter function using tail recursion

Currently I have
(define filter
(λ (f xs)
(letrec [(filter-tail
(λ (f xs x)
(if (empty? xs)
x
(filter-tail f (rest xs)
(if (f (first xs))
(cons (first xs) x)
'()
)))))]
(filter-tail f xs '() ))))
It should be have as a filter function
However it outputs as
(filter positive? '(-1 2 3))
>> (3 2)
but correct return should be (2 3)
I was wondering if the code is correctly done using tail-recursion, if so then I should use a reverse to change the answer?
I was wondering if the code is correctly done using tail-recursion.
Yes, it is using a proper tail call. You have
(define (filter-tail f xs x) ...)
Which, internally is recursively applied to
(filter-tail f
(some-change-to xs)
(some-other-change-to x))
And, externally it's applied to
(filter-tail f xs '())
Both of these applications are in tail position
I should use a reverse to change the answer?
Yep, there's no way around it unless you're mutating the tail of the list (instead of prepending a head) as you build it. One of the comments you received alluded to this using set-cdr! (see also: Getting rid of set-car! and set-cdr!). There may be other techniques, but I'm unaware of them. I'd love to hear them.
This is tail recursive, requires the output to be reversed. This one uses a named let.
(define (filter f xs)
(let loop ([ys '()]
[xs xs])
(cond [(empty? xs) (reverse ys)]
[(f (car xs)) (loop (cons (car xs) ys) (cdr xs))]
[else (loop ys (cdr xs))])))
(filter positive? '(-1 2 3)) ;=> '(2 3)
Here's another one using a left fold. The output still has to be reversed.
(define (filter f xs)
(reverse (foldl (λ (x ys) (if (f x) (cons x ys) ys))
'()
xs)))
(filter positive? '(-1 2 3)) ;=> '(2 3)
With the "difference-lists" technique and curried functions, we can have
(define (fold c z xs)
(cond ((null? xs) z)
(else (fold c (c (car xs) z) (cdr xs)))))
(define (comp f g) (lambda (x) ; ((comp f g) x)
(f (g x))))
(define (cons1 x) (lambda (y) ; ((cons1 x) y)
(cons x y)))
(define (filter p xs)
((fold (lambda (x k)
(if (p x)
(comp k (cons1 x)) ; nesting's on the left
k))
(lambda (x) x) ; the initial continuation, IC
xs)
'()))
(display (filter (lambda (x) (not (zero? (remainder x 2)))) (list 1 2 3 4 5)))
This builds
comp
/ \
comp cons1 5
/ \
comp cons1 3
/ \
IC cons1 1
and applies '() to it, constructing the result list in the efficient right-to-left order, so there's no need to reverse it.
First, fold builds the difference-list representation of the result list in a tail recursive manner by composing the consing functions one-by-one; then the resulting function is applied to '() and is reduced, again, in tail-recursive manner, by virtues of the comp function-composition definition, because the composed functions are nested on the left, as fold is a left fold, processing the list left-to-right:
( (((IC+k1)+k3)+k5) '() ) ; writing `+` for `comp`
=> ( ((IC+k1)+k3) (k5 '()) ) ; and `kI` for the result of `(cons1 I)`
<= ( ((IC+k1)+k3) l5 ) ; l5 = (list 5)
=> ( (IC+k1) (k3 l5) )
<= ( (IC+k1) l3 ) ; l3 = (cons 3 l5)
=> ( IC (k1 l3) )
<= ( IC l1 ) ; l1 = (cons 1 l3)
<= l1
The size of the function built by fold is O(n), just like the interim list would have, with the reversal.

Resources