Prevent recursive function from reallocating a new variable - variables

One of my task in programming class is "Tower Of Hanoi" , the language I was using is Common Lisp and the source code is as follow :
The Code :
Variables:
(defparameter *Source* "Peg 1")
(defparameter *Spare* "Peg 2")
(defparameter *Destination* "Peg 3")
I want the above variable declaraction to be inside the function
(defun towers-of-hanoi (disks)
;disks accept list as parameter , for e.g `(s m l)
(let ((tempPeg))
(if (= (list-length disks) 1)
(format t "Move ~{~A~} from ~A to ~A~%"
(last disks) *Source* *Destination*)
(progn
(setq tempPeg *Spare*)
(setq *Spare* *Destination*)
(setq *Destination* tempPeg)
(towers-of-hanoi (subseq disks 0 (- (list-length disks) 1)))
(setq tempPeg *Spare*)
(setq *Spare* *Destination*)
(setq *Destination* tempPeg)
(format t "Move ~{~A~} from ~A to ~A~%"
(last disks) *Source* *Destination*)
(setq tempPeg *Spare*)
(setq *Spare* *Source*)
(setq *Source* tempPeg)
(towers-of-hanoi (subseq disks 0 (- (list-length disks) 1)))
(setq tempPeg *Spare*)
(setq *Spare* *Source*)
(setq *Source* tempPeg)
(format t "")))))
The Question :
1.)I'm using recursive algorithm to solve this problem , as I know in this algorithm , the 3 variables (Source , Spare and Destination) must interchange with each other (by some rules) . If I place the defvar inside the function , even though I carry out this 3 operations (setq tempPeg *Spare*) (setq *Spare* *Destination*) (setq *Destination* tempPeg) before calling the towers-of-hanoi function again but the function again redefine the 3 variables back through it's original value .
2.)What I wanted to know is that is it possible for me to place the declaraction of the 3 variables inside the function and still able to prevent the function from redefining the same variable for each recursive called?
P/S the assignment only allows me to define a function header that accept disks as the one and only argument but not the Source , Spare , and Destination rod.

There are probably two good options here. The first is that since the function depends on a few values, the function could take them as arguments. That's probably the clearest way to do what you're trying to do, and it makes the recursive calls cleaner, because you don't need to rebind or assign a bunch of variables before making the call. For instance, here's a simple recursive function:
(defun swap-until-x-is-zero (x y)
(print `(swap-until-zero ,x ,y))
(unless (zerop x)
(swap-until-x-is-zero (1- y) (1- x))))
CL-USER> (swap-until-x-is-zero 3 5)
(SWAP-UNTIL-ZERO 3 5)
(SWAP-UNTIL-ZERO 4 2)
(SWAP-UNTIL-ZERO 1 3)
(SWAP-UNTIL-ZERO 2 0)
(SWAP-UNTIL-ZERO -1 1)
(SWAP-UNTIL-ZERO 0 -2)
NIL
Now, if that's supposed to start with some reasonable default values, then those function arguments could be made optional:
(defun swap-until-x-is-zero (&optional (x 3) (y 5))
(print `(swap-until-zero ,x ,y))
(unless (zerop x)
(swap-until-x-is-zero (1- y) (1- x))))
and then you can simply call (swap-until-x-is-zero):
CL-USER> (swap-until-x-is-zero)
(SWAP-UNTIL-ZERO 3 5)
(SWAP-UNTIL-ZERO 4 2)
(SWAP-UNTIL-ZERO 1 3)
(SWAP-UNTIL-ZERO 2 0)
(SWAP-UNTIL-ZERO -1 1)
(SWAP-UNTIL-ZERO 0 -2)
It should be clear how this approach could be applied to the Hanoi problem; you'd simply add three optional arguments to the hanoi and recursively call it with the altered values:
(defun towers-of-hanoi (disks &optional (source "Peg 1") (spare "Peg 2") (destination "Peg 3"))
...
;; instead of:
;; (progn
;; (setq tempPeg *Spare*)
;; (setq *Spare* *Destination*)
;; (setq *Destination* tempPeg)
;; (towers-of-hanoi (subseq disks 0 (- (list-length disks) 1))))
;; we do:
(let ((tempPeg spare))
(towers-of-hanoi (subseq disks 0 (- (list-length disks) 1))
source ; stays the same
destination ; swap destination and spare
spare)) ; swap destination and spare
...)
That said, sometimes there are enough parameters that it's easier to just use special variables (i.e., dynamically scoped variables) for them (though I don't think that this is such a case), and to get those, you can use the special declaration:
(defun towers-of-hanoi (disks)
(declare (special *source* *spare* *destination*))
(let ((tempPeg))
(if (= (list-length disks) 1)
(format t "Move ~{~A~} from ~A to ~A~%" (last disks) *Source* *Destination*)
(progn
(setq tempPeg *Spare*)
(setq *Spare* *Destination*)
(setq *Destination* tempPeg)
(towers-of-hanoi (subseq disks 0 (- (list-length disks) 1)))
...))))
You'll still have to establish the initial bindings of the variables, though, so for the outermost call you'd have to do something like:
(defun hanoi-driver (disks)
(let ((*source* "Peg 1")
(*spare* "Peg 2")
(*destination* "Peg 3"))
(declare (special *source* *spare* *destination*))
(hanoi disks)))
I think that that simply adding the three &optional variables to hanoi is ultimately a cleaner solution, personally.

Your use of lists is not idiomatic. Remember lists in Lisp are singly linked cons cells. All operations which traverse lists or work from the end of lists are inefficient.
To answer your question:
(defun do-something (a)
(let ((foo 42)) ; binding
(labels ((do-something-recursively (b) ; local recursive function
(...)))
(do-something-recursively a))))

Related

Iterating through a nested list using filter or fold Racket

I need to iterate through a list with sublists in Racket using list iteration and filtering, one of the lists is a nested list, I tried using "list?" and "car" to iterate inside but of course that would only apply to the first value of the sublist.
Is there a way to iterate through the whole nested list using list iteration and filtering?
(define (count-evens lst)
(length
(filter
(lambda (x)
(cond
[(and (list? x)
(and (number? (car x))
(eq? (modulo (car x) 2) 0)))
#t]
[(and (number? x)
(eq? (modulo x 2) 0))
#t]
[else
#f]))
lst)))
(count-evens '(1 2 5 4 (8 4 (b (10 3 3))) 3))
=> 3
Should return => 5
I would use a recursive function to do this but the assignment doesn't allow it.
"...assignment doesn't allow [recursive functions]"
Not sure what is allowed for this assignment, but
in ye olden days we processed recursive data structures with stacks...
(define (count-evens lst)
(define (lst-at stack) ;; (car stack) = index in deepest sub-list
;; produce list cursor within lst indexed by stack
(do ([stack (reverse stack) (cdr stack)]
[cursor (list lst) (list-tail (car cursor) (car stack))])
((null? stack) cursor)))
(do ([stack (list 0)
(cond
[(null? (lst-at stack))
(cdr stack)] ;; pop stack
[(pair? (car (lst-at stack)))
(cons 0 stack)] ;; push stack
[else ;; step through current (sub)list
(cons (+ 1 (car stack)) (cdr stack))])]
[count 0
(let ([item (car (lst-at stack))])
(if (and (number? item) (even? item)) (+ 1 count) count))])
((null? (lst-at stack)) count)))
> (count-evens '(1 2 5 4 (8 4 (b (10 3 3))) 3)) ;=>
5

Symbol’s value as variable is void: false when run element-of-setp

Following SICP's instruction, I rewrite its intersection-set as:
(defun intersection-set (set1 set2)
(cond ((or (null set1) (null set2)) '())
((element-of-setp (car set1) set2)
(cons (car set1)
(intersection-set (cdr set1) set2)))
(t (intersection-set (cdr set1) set2))))
(defun element-of-setp(x set)
(cond ((null set) false)
((equal x (car set)) t)
(t (element-of-setp x (cdr set)))))
(intersection-set (list 1 2) (list 2 3 4))
Running it reports the following error:
element-of-setp: Symbol’s value as variable is void: false
However, element-of-setp on its own seems to work properly:
#+begin_src emacs-lisp :tangle yes
(defun element-of-setp(x set)
(cond ((null set) false)
((equal x (car set)) t)
(t (element-of-setp x (cdr set)))))
(element-of-setp 1 (list 1 2 3))
#+end_src
#+RESULTS:
: t
What's the problem?
However, element-of-setp on its own seems to work properly:
Unfortunately, the test you used did not cover all the possible cases.
If you try instead:
(element-of-setp 5 (list 1 2 3))
Then the function is going to reach the case where the list is empty, and in that it will evaluate false, which is most likely undefined; as stated in the comment, boolean values in Emacs-Lisp are represented by nil and non-nil values (atoms).

Two racket modules colliding

I am requiring two modules to my file:
(require sicp) ; contains set-car! and set-cdr!
(require (planet dyoo/sicp-concurrency:1:2/sicp-concurrency)) ; contains procedures parallel-execute and test-and-set!
Problem: both libraries use different flavors of scheme. The sicp-concurrency uses mzscheme. Requiring this module prevented me from using else in a cond clause.
Is there a way to prevent the features of mzscheme in sicp-concurrency while still making use of the procedures I needed?
I have updated Danny Yoo's code to Racket 7.
Get the new file "sicp-concurrency.rkt" here:
https://gist.github.com/soegaard/d32e12d89705c774b71ee78ef930a4bf
Save the file in the same folder as your program file.
Here is an example of use:
#lang sicp
(#%require "sicp-concurrency.rkt")
(define (test-1)
(define x 10)
(parallel-execute (lambda () (set! x (* x x)))
(lambda () (set! x (+ x 1))))
x)
(define (test-2)
(define x 10)
(define s (make-serializer))
(parallel-execute (s (lambda () (set! x (* x x))))
(s (lambda () (set! x (+ x 1)))))
x)
(test-1)
(test-1)
(test-1)
(test-1)
(test-1)

Custom Scheme indexing function returns list-external value

I'm a newbie to scheme programming and I was writing small codes when I encountered the following issue and couldn't reason about it satisfactorily.
(define (at_i lst i)
(if (eq? i 0)
(car lst)
(at_i (cdr lst)
(- i 1) )))
Evaluation of (at_i '(1 2 3 4) 0) returns 1.
Now lets define same procedure with a lambda syntax.
(define (at_i lst i)
(lambda (vec x)
(if (eq? x 0)
(car vec)
(at_i (cdr vec)
(- x 1) )))
lst i)
But now Evaluation of (at_i '(1 2 3 4) 0) returns 0, which is not in the list and in general, it returns element at index-1.
I don't understand why this is happening.
Note: I just realized its not returning element at index - 1 but the index itself. The reason for this has been well explained below by #Renzo. Thanks!
First, you should indent properly the code if you intend to learn the language, since code indentation is very important to understand programs in Scheme and Lisp-like languages.
For instance, your function correctly indented is:
(define (at_i lst i)
(lambda (vec x)
(if (eq? x 0)
(car vec)
(at_i (cdr vec) (- x 1))))
lst
i)
From this you can see that you are defining the function at_i exactly as before in terms of a function with two parameters (lst and i), and whose body is constitued by three expressions: the first lambda (vec x) ... (- x 1)))), which is an (anonymous) function (lambda) which is not called or applied, the second, which is the first parameter lst, and finally the third which is the second parameter i. So, when the function at_i is called with two arguments, the result is the evaluation of the three expressions in sequence, the first two values are discarded (the function and the value of lst), and the result is the value of the second parameter i. This is reason for which the result of (at_i '(1 2 3 4) 0) is 0, since it is the value of i.
A proper redefinition of the function in lambda form would be the following, for instance:
(define at_i
(lambda (vec x)
(if (eq? x 0)
(car vec)
(at_i (cdr vec) (- x 1)))))
(at_i '(1 2 3 4) 0) ;; => 1
in which you can see that the name at_i, through the define, is associated to a two parameter function which calculates correctly the result.
eq? is memory object equality. Only some Scheme implementations interpret (eq? 5 5) as #t. Use = for numbers, eqv? for values, and equal? for collections.
(define (index i xs) ; `index` is a partial function,
(if (= i 0) ; `i` may go out of range
(car xs)
(index (- i 1) ; Tail recursion
(cdr xs) )))
Your second function returns the index because you missed parenthesis around the lambda's application. It should be
(define (index i xs)
((lambda (i' xs')
(if (= i' 0)
(car xs')
(index (- i' 1) ; Not tail-recursive
(cdr xs') )))
i xs))
But this is verbose and differs semantically from the first formulation.
You say you are defining the "same procedure with a lambda syntax", but you are not. That would be (define at_i (lambda lst i) ...). Instead, you are effectively saying (define (at_i lst i) 1 2 3), and that is 3, of course.
In your particular case, you defined the procedure at_i to return (lambda (vec x) ...), lst and i. Now, if you call (at_i '(1 2 3 4) 0), the procedure will return 0, since that is the value of i at this point.

application: not a procedure racket

i am new to racket. i am trying create a list from the input of the user and when the value 0 is entred the first three elements are printed.
here is the code:
#lang racket
(define lst '())
(define (add)
(define n(read))
(if (= n 0)
;then
(
list (car lst) (cadr lst) (caddr lst)
)
;else
(
(set! lst (append lst (list n)))
(add)
)
)
)
(add)
i tested the program with the values 1 2 3 4 5 0
but i keep getting this error:
application: not a procedure;
expected a procedure that can be applied to arguments
given: #<void>
arguments...:
'(1 2 3)
can anyone help me figure out what's wrong.
If you have more than one expression in the "then" or "else" parts, you must enclose them inside a begin, because a pair of () in Scheme are used for function application - that explains the error you're getting. Try this:
(define (add)
(define n (read))
(if (= n 0)
; then
(list (car lst) (cadr lst) (caddr lst))
; else
(begin
(set! lst (append lst (list n)))
(add))))
I had a similar problem, in a function i called a parameter with the same name of a structure, so, trying to create an instance of that structure i got the same error.
example:
> (struct example (param1 param2) #:transparent)
> (define e (example 1 2))
> e
(example 1 2)
> (define (fn e)
(example (example-param1 e) 0))
> (fn e)
(example 1 0)
> (define (fn example)
(example (example-param1 example) 0))
> (fn e)
application: not a procedure;
expected a procedure that can be applied to arguments
given: (example 1 2)
arguments...:
I hope this helps
Your code have a few problems, for example it will fail if you enter less than 3 elements. Also, it is not considered good style to define variables at the module level.
I'd suggest the following:
(define (add)
(define (sub cnt lst)
(define n (read))
(if (= n 0)
(reverse lst)
(if (< cnt 3)
(sub (add1 cnt) (cons n lst))
(sub cnt lst))))
(sub 0 '()))