How to list all intermediate steps of evaluation in Scheme - scheme

For example if there's the expression:
(map (lambda(x) (add1 x)) '(1 2 3))
It evaluates to:
'(2 3 4)
How to display all the intermediate steps which in this case will be:
(map (lambda(x) (add1 x)) '(2 2 3))
(map (lambda(x) (add1 x)) '(2 3 3))

I think the best way to do this would be to start by making your own lambda calculus interpreter and adding the extra scheme features you need, and then modifying that interpreter to produce the execution trace that you want.
This could get you started with writing an interpreter http://matt.might.net/articles/implementing-a-programming-language/

Related

Combinations with pairs

I am trying to combine a list of pairs in scheme to get all possible combinations. For example:
((1 2) (3 4) (5 6)) --> ((1 3 5) (1 3 6) (1 4 5) (1 4 6) (2 3 5) (2 3 6) (2 4 5) (2 4 6))
I've been able to solve it (I think) using a "take the first and prepend it to the cdr of the procedure" with the following:
(define (combine-pair-with-list-of-pairs P Lp)
(apply append
(map (lambda (num)
(map (lambda (pair)
(cons num pair)) Lp)) P)))
(define (comb-N Lp)
(if (null? Lp)
'(())
(combine-pair-with-list-of-pairs (car Lp) (comb-N (cdr Lp)))))
(comb-N '((1 2)(3 4)(5 6)))
; ((1 3 5) (1 3 6) (1 4 5) (1 4 6) (2 3 5) (2 3 6) (2 4 5) (2 4 6))
However, I've been having trouble figuring out how I can use a procedure that only takes two and having a wrapper around it to be able to define comb-N by calling that function. Here it is:
(define (combinations L1 L2)
(apply append
(map (lambda (L1_item)
(map (lambda (L2_item)
(list L1_item L2_item))
L2))
L1)))
(combinations '(1) '(1 2 3))
; ((1 1) (1 2) (1 3))
I suppose the difficulty with calling this function is it expects two lists, and the recursive call is expecting a list of lists as the second argument. How could I call this combinations function to define comb-N?
difficulty? recursion? where?
You can write combinations using delimited continuations. Here we represent an ambiguous computation by writing amb. The expression bounded by reset will run once for each argument supplied to amb -
(define (amb . lst)
(shift k (append-map k lst)))
(reset
(list (list (amb 'a 'b) (amb 1 2 3))))
((a 1) (a 2) (a 3) (b 1) (b 2) (b 3))
how it works
The expression is evaluated through the first amb where the continuation is captured to k -
k := (list (list ... (amb 1 2 3)))
Where applying k will supply its argument to the "hole" left by amb's call to shift, represented by ... above. We can effectively think of k in terms of a lambda -
k := (lambda (x) (list (list x (amb 1 2 3)))
amb returns an append-map expression -
(append-map k '(a b))
Where append-map will apply k to each element of the input list, '(a b), and append the results. This effectively translates to -
(append
(k 'a)
(k 'b))
Next expand the continuation, k, in place -
(append
(list (list 'a (amb 1 2 3))) ; <-
(list (list 'b (amb 1 2 3)))) ; <-
Continuing with the evaluation, we evaluate the next amb. The pattern is continued. amb's call to shift captures the current continuation to k, but this time the continuation has evolved a bit -
k := (list (list 'a ...))
Again, we can think of k in terms of lambda -
k := (lambda (x) (list (list 'a x)))
And amb returns an append-map expression -
(append
(append-map k '(1 2 3)) ; <-
(list (list 'b ...)))
We can continue working like this to resolve the entire computation. append-map applies k to each element of the input and appends the results, effectively translating to -
(append
(append (k 1) (k 2) (k 3)) ; <-
(list (list 'b ...)))
Expand the k in place -
(append
(append
(list (list 'a 1)) ; <-
(list (list 'a 2)) ; <-
(list (list 'a 3))) ; <-
(list (list 'b (amb 1 2 3))))
We can really start to see where this is going now. We can simplify the above expression to -
(append
'((a 1) (a 2) (a 3)) ; <-
(list (list 'b (amb 1 2 3))))
Evaluation now continues to the final amb expression. We will follow the pattern one more time. Here amb's call to shift captures the current continuation as k -
k := (list (list 'b ...))
In lambda terms, we think of k as -
k := (lambda (x) (list (list 'b x)))
amb returns an append-map expression -
(append
'((a 1) (a 2) (a 3))
(append-map k '(1 2 3))) ; <-
append-map applies k to each element and appends the results. This translates to -
(append
'((a 1) (a 2) (a 3))
(append (k 1) (k 2) (k 3))) ; <-
Expand k in place -
(append
'((a 1) (a 2) (a 3))
(append
(list (list 'b 1)) ; <-
(list (list 'b 2)) ; <-
(list (list 'b 3)))) ; <-
This simplifies to -
(append
'((a 1) (a 2) (a 3))
'((b 1) (b 2) (b 3))) ; <-
And finally we can compute the outermost append, producing the output -
((a 1) (a 2) (a 3) (b 1) (b 2) (b 3))
generalizing a procedure
Above we used fixed inputs, '(a b) and '(1 2 3). We could make a generic combinations procedure which applies amb to its input arguments -
(define (combinations a b)
(reset
(list (list (apply amb a) (apply amb b)))))
(combinations '(a b) '(1 2 3))
((a 1) (a 2) (a 3) (b 1) (b 2) (b 3))
Now we can easily expand this idea to accept any number of input lists. We write a variadic combinations procedure by taking a list of lists and map over it, applying amb to each -
(define (combinations . lsts)
(reset
(list (map (lambda (each) (apply amb each)) lsts))))
(combinations '(1 2) '(3 4) '(5 6))
((1 3 5) (1 3 6) (1 4 5) (1 4 6) (2 3 5) (2 3 6) (2 4 5) (2 4 6))
Any number of lists of any length can be used -
(combinations
'(common rare)
'(air ground)
'(electric ice bug)
'(monster))
((common air electric monster)
(common air ice monster)
(common air bug monster)
(common ground electric monster)
(common ground ice monster)
(common ground bug monster)
(rare air electric monster)
(rare air ice monster)
(rare air bug monster)
(rare ground electric monster)
(rare ground ice monster)
(rare ground bug monster))
related reading
In Scheme, we can use Olivier Danvy's original implementation of shift/reset. In Racket, they are supplied via racket/control
(define-syntax reset
(syntax-rules ()
((_ ?e) (reset-thunk (lambda () ?e)))))
(define-syntax shift
(syntax-rules ()
((_ ?k ?e) (call/ct (lambda (?k) ?e)))))
(define *meta-continuation*
(lambda (v)
(error "You forgot the top-level reset...")))
(define abort
(lambda (v)
(*meta-continuation* v)))
(define reset-thunk
(lambda (t)
(let ((mc *meta-continuation*))
(call-with-current-continuation
(lambda (k)
(begin
(set! *meta-continuation* (lambda (v)
(begin
(set! *meta-continuation* mc)
(k v))))
(abort (t))))))))
(define call/ct
(lambda (f)
(call-with-current-continuation
(lambda (k)
(abort (f (lambda (v)
(reset (k v)))))))))
For more insight on the use of append-map and amb, see this answer to your another one of your questions.
See also the Compoasable Continuations Tutorial on the Scheme Wiki.
remarks
I really struggled with functional style at first. I cut my teeth on imperative style and it took me some time to see recursion as the "natural" way of thinking to solve problems in a functional way. However I offer this post in hopes to provoke you to reach for even higher orders of thinking and reasoning. Recursion is the topic I write about most on this site but I'm here saying that sometimes even more creative, imaginative, declarative ways exist to express your programs.
First-class continuations can turn your program inside-out, allowing you to write a program which manipulates, consumes, and multiplies itself. It's a sophisticated level of control that's part of the Scheme spec but only fully supported in a few other languages. Like recursion, continuations are a tough nut to crack, but once you "see", you wish you would've learned them earlier.
As suggested in the comments you can use recursion, specifically, right fold:
(define (flatmap foo xs)
(apply append
(map foo xs)))
(define (flatmapOn xs foo)
(flatmap foo xs))
(define (mapOn xs foo)
(map foo xs))
(define (combs L1 L2) ; your "combinations", shorter name
(flatmapOn L1 (lambda (L1_item)
(mapOn L2 (lambda (L2_item) ; changed this:
(cons L1_item L2_item)))))) ; cons NB!
(display
(combs '(1 2)
(combs '(3 4)
(combs '(5 6) '( () )))))
; returns:
; ((1 3 5) (1 3 6) (1 4 5) (1 4 6) (2 3 5) (2 3 6) (2 4 5) (2 4 6))
So you see, the list that you used there wasn't quite right, I changed it back to cons (and thus it becomes fully the same as combine-pair-with-list-of-pairs). That way it becomes extensible: (list 3 (list 2 1)) isn't nice but (cons 3 (cons 2 (cons 1 '()))) is nicer.
With list it can't be used as you wished: such function receives lists of elements, and produces lists of lists of elements. This kind of output can't be used as the expected kind of input in another invocation of that function -- it would produce different kind of results. To build many by combining only two each time, that combination must produce the same kind of output as the two inputs. It's like +, with numbers. So either stay with the cons, or change the combination function completely.
As to my remark about right fold: that's the structure of the nested calls to combs in my example above. It can be used to define this function as
(define (sequence lists)
(foldr
(lambda (list r) ; r is the recursive result
(combs list r))
'(()) ; using `()` as the base
lists))
Yes, the proper name of this function is sequence (well, it's the one used in Haskell).

How to invert the predicate here?

I have the following filter procedure:
; (2) filter
(define (filter test sequence)
; return a list of the elements that pass the predicate test
(let ((elem (if (null? sequence) nil (car sequence)))
(rest (if (null? sequence) nil (cdr sequence))))
(cond ((null? sequence) nil)
((test elem) (cons elem (filter test rest)))
(else (filter test rest)))))
And here would be an example of using it to return the even-numbered elements of a list:
(define even? (lambda (x) (= (modulo x 2) 0)))
(define sequence '(1 2 3 4 5 8 9 11 13 14 15 16 17))
(filter even? sequence)
; (2 4 8 14 16)
Is there a simple way to use the not test to invert the selection? For example, I thought the following might work:
(filter (not even?) sequence)
But it returns an error. I can define odd separately, of course:
(define odd? (lambda (x) (not (even? x))))
But I'm trying not to do this. Is there a way to write the odd procedure without defining it directly, but instead using the not directly like I'm trying to do above?
There is a complement function in Common Lisp that does what I think you are looking for. complement is a higher-order procedure that takes a procedure as its argument, and returns a procedure that takes the same arguments as the input procedure and performs the same actions, but the returned truth value is inverted.
Racket has a similar procedure, negate, and it is easy enough to implement this in Scheme:
(define (complement f)
(lambda xs (not (apply f xs))))
> (filter even? '(1 2 3 4 5))
(2 4)
> (filter (complement even?) '(1 2 3 4 5))
(1 3 5)
> (> 1 2 3 4 5)
#f
> ((complement >) 1 2 3 4 5)
#t
And in Racket:
scratch.rkt> (filter even? '(1 2 3 4 5))
'(2 4)
scratch.rkt> (filter (negate even?) '(1 2 3 4 5))
'(1 3 5)
scratch.rkt> (> 1 2 3 4 5)
#f
scratch.rkt> ((negate >) 1 2 3 4 5)
#t
The general answer to this is to simply compose not and the function you care about. Racket has a compose function which does this, but you can easily write a simple one yourself:
(define (compose-1 . functions)
;; simple-minded compose: each function other than the last must
;; take just one argument; all functions should return just one
;; value.
(define (compose-loop fns)
(cond
((null? fns)
(λ (x) x))
((null? (cdr fns))
(car fns))
(else
(λ (x) ((car fns) ((compose-loop (cdr fns)) x))))))
(compose-loop functions))
Making it efficient and more general takes more work of course.
Then you can define odd? (which is already defined of course):
(define odd? (compose-1 not even)
Or in fact define a more general CL-style complement function:
(define (complement f)
(compose-1 not f))
One option is to write an invert function which will curry things along (so the initial function still accepts one argument) until the final evaluation occurs:
(define invert (lambda (func) (lambda (x) (not (func x)))))
(define sequence '(1 2 3 4 5 6 8 9 11 13 14 15 16 17))
(filter (invert even?) sequence)
; (1 3 5 9 11 13 15 17)

Scheme append function workflow

Hello I am looking at the append function
(define ( append x y )
(if (null? x)
y)
(cons (car x)
(append (cdr x)
y))))
I understand how the list is generated but when the first list x is empty we directly return y,I don't see how we connect it to the first list "x".Does the process go like this (cons a1(cons a2....(cons an y).. )) and how does the program understand to plug in y at (cons an y),Is it because in the end the expression is (cons an-1 ,append (cdr x) y ) and the result of (append (cdr x ),y) is y?
Your function has an error in it such that is in parsing has one closing parens too much in the end. I thin kit's because you close if just after y. Because of that it will always do the last expression and it fails when x is empty.
The correct append looks like this:
(define (append x y)
(if (null? x)
y
(cons (car x)
(append (cdr x)
y))))
I like to explain recursive functions by simplest to general so we start off with the obvious, the base case:
(append '() '(3 4))
This will be #t for x being null? and the result is (3 4). Now lets try with a one element list as x:
(append '(2) '(3 4))
This is #f for x being `null? thus you can substitute it with:
(cons (car '(2))
(append (cdr '(2))
'(3 4)))
We can evaluate the accessors on '(2):
(cons 2 (append '() '(3 4))
Since we did the base case before we know the answer to the append part, which is '(3 4) so we end up with:
(cons 2 '(3 4)) ; ==> (2 3 4)
Lets do a new x:
(append '(1 2) '(3 4))
Here as the previous x is not null? so you substitute with the alternative again:
(cons (car '(1 2))
(append (cdr '(1 2))
'(3 4)))
As the previous time we can evaluate the accessors:
(cons 1
(append '(2)
'(3 4)))
Notice that again we have familiar arguments to append so we could just substitute that with our last result, however I take the step before so you see the pattern you noticed:
(cons 1 (cons 2 (append '() '(3 4)))) ; ==>
(cons 1 (cons 2 '(3 4))) ; ==>
(cons 1 '(2 3 4)) ; ==>
; ==> (1 2 3 4)
So if you have a 12 element x it gets 12 cons nested before hitting the base case and then it evaluates the the inner to the outer since list are always created from end to beginning since the functions need to evaluate their arguments before applying.

Scheme operation on a function

Is it possible to do an operation on a previous function, i have a list of values say (1,2,3,4,5), first function needs to multiply them by 2, while 2nd function adds 1 to result of previous function, so first we would get (2,4,6,8,10), and then (3,5,7,9,11) i got this, function g does extra work, is it possible nstead of doing operations on the element do it on function F or results from function F
#lang racket
(define test (list 1 1 2 3 5))
(define (F)
(map (lambda (element) (* 2 element))
test))
(define (G)
(map (lambda (element) (+ 1 (* 2 element)))
test))
First you need to correctly define your procedures to take a list parameter (called lst in this case):
(define (F lst)
(map (lambda (e) (* 2 e)) lst))
(define (G lst)
(map add1 lst))
Then
> (F '(1 2 3 4 5))
'(2 4 6 8 10)
> (G '(2 4 6 8 10))
'(3 5 7 9 11)
or, if you need to combine both procedures:
> (G (F '(1 2 3 4 5)))
'(3 5 7 9 11)
This is a follow-up to your previous question. As stated in my answer there, you should pass the right parameters to the functions - in particular, pass the input lists as parameter, so you can use the result from one function as input for the next function:
(define test (list 1 1 2 3 5))
(define (multiply-list test)
(map (lambda (element) (* 2 element))
test))
(define (add-list test)
(map (lambda (element) (+ 1 element))
test))
Now, if we want to add one to each element in the input list:
(add-list test)
=> '(3 3 5 7 11)
Or if we want to multiply by two each element in the input list:
(multiply-list test)
=> '(2 2 4 6 10)
And if we want to add one first, then multiply by two we can chain the functions! the result from one becomes the input for the other, and the final result will be as follows:
(multiply-list (add-list test))
=> '(6 6 10 14 22)
NB! You have tagged scheme but you use racket (the language). Not all of my examples will work in scheme.
Yes! you even do it yourself in your definition of G where you add a value and the result of a multiplication.
Its possible to chain map
(map f3 (map f2 (map f1 lst)))
Thus if you instead make a function that takes a list and doubles it:
(define (list-double lst)
(map (lambda (x) (* x 2)) lst))
You can chain it to quadruple it:
(define (list-quadruple lst)
(list-double (list-double lst)))
Now it's not optimal to chain map if you can avoid it. Instead you can compose the procedures together:
(define (double x) (* x 2))
(define (list-quadrouple lst)
(map (compose1 double double) lst))
compose1 here is the same as making a anonymous function where you chain the arguments. Eg. the last would be (lambda (x) (double (double x))). A more complex one compose can do more than one value between procedures. eg. (compose + quotient/remainder)

What's wrong with this append?

Racket is giving me a contract violation for the following code:
(define (fringe x)
(append (car x) (fringe (cdr x))))
Any ideas what's wrong with it?
It happens because (car x) is not returning a list (it's hard to tell for sure without knowing the actual value of x that's rising the error). append is an operation defined between two lists. If you want to add an element at the head of a list, use cons instead of append.
This is what I mean:
(append 1 '(2 3))
=> append: expected argument of type <proper list>; given 1
(append '(1) '(2 3))
=> '(1 2 3)
(cons 1 '(2 3)) ; the recommended way!
=> '(1 2 3)

Resources