How to continue to the next iteration using let in Racket? - racket

I am trying to modify the code from bellow so that when (when (= i 6) (loop (+ 1 i))) appears the loop to move to the next iteration without continuing doing with the "do stuff" part.
(let loop ([i 0])
(cond
[(= i 10) (printf "end\n")]
[else
(when (= i 6) (loop (+ 1 i)))
(define x (+ 1 2)) ; do stuff
(printf "~a\n" i)
(loop (+ 1 i))]))
Basically what I'm trying to obtain is something similar to "continue" from C# (like the code from bellow), but using let in Racket:
for (int i = 0; i < 10; i++)
{
if (i == 6)
{
continue;
}
Console.WriteLine(i);
}
If that's not possible (or recommended) in Racket, what can I use as an alternative?

Rewrite without continue by negating the condition:
for (int i = 0; i < 10; i++)
{
if (i != 6)
{
Console.WriteLine(i);
}
}
then as while instead of for:
int i = 0;
while (i < 10)
{
if (i != 6)
{
Console.WriteLine(i);
}
i += 1;
}
and then this has almost exactly the same form:
(let loop ([i 0])
(when (< i 10)
(unless (= i 6)
(printf "~a\n" i))
(loop (+ 1 i))))

You can get the desired effect by adding one extra case to the cond expression. This is equivalent to your C# example:
(let loop ([i 0])
(cond [(= i 10) (printf "end\n")]
[(= i 6) (loop (add1 i))]
[else
; do some other stuff
(printf "~a\n" i)
(loop (add1 i))]))
You can "do stuff" after each condition, as long as the last expression is either the exit to the recursion or the recursive call - just remember that only the value of the last expression will be returned, and if you need to pass values to the next iteration, you'll need to add parameters to the recursive call.

Related

Questions about replacing while and if statements with lisp

I want to change the code below to Lisp code, but I keep getting errors in grammar. How do I fix the if statement?
int promising(int i)
{
int k = 1;
while (k < i)
{
if (col[i] == col[k] || abs(col[i] - col[k]) == abs(i - k))
return 0;
k++;
}
return 1;
}
Below is the one I changed to the Lisp code.
(setq col (list 0 0 0 0))
(DEFUN promising (i)
(let ((k 1)) ; k =1
(loop while (< k i)
do((if (or ( = (nth i col) (nth k col))
(= ( abs((setq a (- (nth i col) (nth k col)))))
( abs((setq b (- i k ))))))
(return-from promising 0)))
do (setq k (1+ k)))
(return-from promising 1))
)
It is difficult for me to flexibly change the complicated condition of the if statement to the lisp code.
You are doing "C-in-Lisp". Trying to directly translate C (or for that matter, C++/Java/C#/Python ...) programs into Lisp will often lead to poor code, and you should be better off trying to understand how those problems are sovled in Lisp.
That being said:
You should not use (setq col <whatever>) at the toplevel. Global variables are introduced using defvar or defparameter and their name is of the form *variable-name* to distinguish them from other variables. This is because they have different scoping rules, and behave differently (i.e. they are not equivalent to other languages' global variables). In particular, using setq with a variable that has not been declared with defvar or defparameter is undefined behaviour, and most implementations will allow it, but they will then create this global variable. You generally don't want that. To sum up: either use (defvar *col* (list 0 0 ...)) if you need this really is a global variable, or simply use (let ((col (list 0 ...))) <more-code>) where you need it.
loop is a complicated construct. This is, in itself, another mini-language that you have to learn on top of Lisp. In particular, if all you ever want to do is "loop with some variable between some bounds and increment it by some value at each step", use
(loop for k from 1 do ...) ;; this introduces a local variable k, incremented by 1 at each step, with no upper bound
(loop for k from 1 to 10 do ...) ;; same, but only loop until k reaches 10
(loop for k from 1 to 10 by 3 do ...) same, but increments k by 3 at each step
Other constructs are available. Read this section of Practical Common Lisp for a good introduction, and the relevant CLHS section for a technical description and documentation.
Please follow conventions for whitespace this makes it much easier to read. For example, never place a parenthesis alone on its line (e.g. your very last parenthesis), and ( abs((setq b (- i k )))) should really be written (abs ((setq b (- i k)))) (ignoring the fact that this is incorrect, see below ...). As far as style is concerned, you also need to fix the indentation, and don't write DEFUN is uppercase, it is unnecessary and looks weird.
You cannot place extra parenthensis just to group things together, parenthesis have semantic meaning. In particular, in most cases, calling a function or using pretty much any special operator is done by (<operator-name> <first-arg> <second-arg> ... ). You almost never have 2 consecutive opening parenthesis.
Why are you using (setq a ...) and (setq b ...) in your loop ? Neither a nor b is ever declared or used anywhere else.
If you want to access specific elements of a list, don't use a list, use a vector. In particular, several calls to the nth function is often the sign that you really should have been using a vector.
A correct version of your code, using a few loop facilities, and still assuming that col is a list (which is should not be) although there would be other loop constructs making this even clearer ...
(defun promising (i)
(loop for k from 1 below i
for col-k = (nth k col)
do (when (or (= (nth i col) (nth k col))
(= (abs (- (nth i col) (nth k col)))
(abs (- i k))))
(return-from promising 0)))
1)
Note that this code is incredibly inefficient and this is why I suggested not to translate directly from C to Lisp. In particular, although you traverse a list (you access the k-th element at the k-th step), your code calls nth at each step instead of traversing the list ! You also compute (nth i col) at each step, which is already useless in C (it is constant so doesn't need to be recomputed at every step), but is catastrophic here. This should really be:
(defun promising (i)
(let ((col-i (nth i col)))
(loop for k from 1 below i
for col-k in (cdr col) ;; you start from the index 1, not 0
do (when (or (= col-i col-k)
(= (abs (- col-i col-k))
(abs (- i k))))
(return-from promising 0))))
1)
There are several mistakes in the code.
Incorrect function calls
(DEFUN promising (i)
(let ((k 1)) ; k =1
(loop while (< k i)
do((if (or ( = (nth i col) (nth k col))
;; ^^
;; Incorrect
)
And also here:
(setq col (list 0 0 0 0))
(DEFUN promising (i)
(let ((k 1)) ; k =1
(loop while (< k i)
do((if (or ( = (nth i col) (nth k col))
(= ( abs((setq a (- (nth i col) (nth k col)))))
;; ^^
;; Incorrect
( abs((setq b (- i k ))))))
;; ^^
;; Incorrect
(return-from promising 0)))
do (setq k (1+ k)))
(return-from promising 1))
)
The loop macro have 2 do keywords
(setq col (list 0 0 0 0))
(DEFUN promising (i)
(let ((k 1)) ; k =1
(loop while (< k i)
do((if (or ( = (nth i col) (nth k col))
;; ^^
;; First do
(= ( abs((setq a (- (nth i col) (nth k col)))))
( abs((setq b (- i k ))))))
(return-from promising 0)))
do (setq k (1+ k)))
;; ^^
;; Second do
(return-from promising 1))
)
return-from is used several times
return-from is usually not present in Common Lisp code, this is pretty much like C goto, something developers try to avoid.
Incoherent setq defining a and b (probably old code)
(setq col (list 0 0 0 0))
(DEFUN promising (i)
(let ((k 1)) ; k =1
(loop while (< k i)
do((if (or ( = (nth i col) (nth k col))
(= ( abs((setq a (- (nth i col) (nth k col)))))\
;; ^^^^^^
;; ??
( abs((setq b (- i k ))))))
;; ^^^^^^
;; ??
Weird incrementation scheme
(setq k (1+ k))
While being correct, Common Lisp programmers will simply use the increment function:
(incf k)
Final code
The code you might looking for should be close to that one:
(defun promising (i)
(let ((k 1))
(loop while (< k i) do
(if (or (= (nth i col) (nth k col))
(= (abs (- (nth i col) (nth k col)))
(abs (- i k ))))
(return-from promising 0))
(incf k))
;; return value
k))
Please note that the code is not equivalent to the C version, because the data structure is completely different. In the C version, the access to the data will be very fast O(1). The Common Lisp version will be slow if you have a large number of elements O(n). You can be fast with Common Lisp if you replace your list by an array/vector.

writing nested while loops in racket

I was trying to use the while loop package in racket to write nested loops like so:
(define i 0)
(define j 0)
(while (< i 10)
(while (< j 10) (printf "~a ~a~n" i j) (set! j (+ j 1)))
(set! i (+ i 1)) )
but for some reason the inner loop was only executed once. Can someone tell me what I did wrong?
Consider the value of j at the end of the first series of iterations: it is 10.
Then i is incremented by 1 and the inner loop is started again. But now j is 10 and the loop is exited immediately!
To correct this problem, simply re-initialize the value of j before any execution of the inner loop, for instance:
(define i 0)
(define j 0)
(while (< i 10)
(set! j 0)
(while (< j 10) (printf "~a ~a~n" i j) (set! j (+ j 1)))
(set! i (+ i 1)) )

Common Lisp: Function returns function name

I am currently trying to solve problem 1 from projecteuler.net. Evaluation of this function only returns the name of the function. What am I doing wrong?
(defun nSum (n sum)
(if ( n = 0) ( sum) )
(cond ( (mod n 5) = 0) ( nSum ( - n 1) (+ sum n)) ( (mod n 3) = 0) (nSum(- n 1) (+ sum n)) (nSum (- n 1) (+ sum n))
)
)
(setq sum (nSum 100 0))
(write sum)
Errors
Evaluation of this function only returns the name of the function.
I cannot replicate this, how did you test your code, under which environment?
With SBCL, here is what evaluating the defun form prints:
; in: DEFUN NSUM
; (N = 0)
;
; caught WARNING:
; undefined variable: =
The = symbol is being used in a position where it is evaluated as a variable. If you want to call the function bound to =, that is (function =), which can be written also #'=, then you have to write (= ... ...).
; caught STYLE-WARNING:
; undefined function: N
Since you wrote (N = 0), i.e. with N as the first element of a form under normal evaluation rules, the code tries to call function N. In your case, you have no such function defined.
; (COND ((MOD N 5) = 0) (NSUM (- N 1) (+ SUM N)) ((MOD N 3) = 0)
; (NSUM (- N 1) (+ SUM N)) (NSUM (- N 1) (+ SUM N)))
; --> IF
; ==>
; (IF NSUM
; (PROGN (- N 1) (+ SUM N))
; (IF (MOD N 3)
; (PROGN = 0)
; (IF NSUM
; (PROGN (- N 1) (+ SUM N))
; (IF NSUM
; (PROGN # #)
; NIL))))
;
; caught WARNING:
; undefined variable: NSUM
You are writing cond clauses, and in that context, each clause is supposed to be a list matching (test . body), i.e. a test expression followed by the case body (possibly empty). You wrote:
(cond ( (mod n 5) = 0) ( nSum ( - n 1) (+ sum n)) ...)
In the above, you have two clauses, one which (tries to) tests whether N is divisible by 5, and the other which test if nSum is true.
; (SUM)
;
; caught STYLE-WARNING:
; undefined function: SUM
You added parentheses around SUM, which means you want to call function SUM (currently undefined). Parentheses matter in Lisp.
Fixing errors and formatting
Here is your code after fixing the previous errors and formatting it according to Lisp style rules:
(defun nSum (n sum)
(if (= n 0)
sum
(cond
((= 0 (mod n 5)) (nSum (- n 1) (+ sum n)))
((= 0 (mod n 3)) (nSum (- n 1) (+ sum n)))
(t (nSum (- n 1) (+ sum n))))))
Your code does not compute the desired function. Please read Gwang-Jin Kim's answer to see how to compute it a tail-recursive way, or below for a loop-based one.
Some additional remarks w.r.t. style:
You are not supposed to use snakeCase in Lisp, use instead dashes to separate words, known humbly as lisp-case (and apparently, also as kebab-case).
Your if and cond can be merged together. Also, be careful about negative N.
You can do (or test1 test2) when both tests lead to the same code being executed. This avoids code duplication.
Alternative implementation
Use LOOP:
(defun euler-1 (n)
(loop
for i below n
when (or (zerop (mod i 3))
(zerop (mod i 5)))
sum i))
(defun nsum (n)
(labels ((inner-nsum (m sum) ; using `labels` define local recursive function
(cond ((= m 0) sum)
((= (mod m 3) 0) (inner-nsum (- m 1) (+ m sum)))
((= (mod m 5) 0) (inner-nsum (- m 1) (+ m sum)))
(t (inner-nsum (- m 1) sum)))))
(inner-nsum (- n 1) 0))) ; call it with n decremented by 1
; to implement "below n"
(nsum 10) ;; 23 ; test successful!
(nsum 1000) ;; 233168
You should use eq for equality test (or perhaps equal; for integers it is the same), or = for comparing numbers. And there is no infix operator in Common Lisp. So ( n = 0) should be something like (eq n 0) or (= n 0) etc.

application: not a procedure scheme

i am new to racket. I tried to do lab work, but...
#lang scheme
(define lab2
(lambda (currentList counter result)
((let countdown ((i (- (length currentList) 1)))
(if (= i 0) (display result)
(begin
(if (pair? (list-ref currentList i)) ;1 if element is list
(if (> (+ 1 counter) result) ;1 if counter > currentResult
((set! counter (+ 1 counter)) (set! result (+ 1 result)) (countdown(- i 1))) ;2 then counter++, result++
((set! counter (+ 1 counter)) (countdown(- i 1)))) ;2 else counter++
((set! counter 0) (countdown(- i 1)))) ;1 else counter=0
))))))
testing: (lab2 '(9 9 9 (0) (0) (0) (0) 9 9 9 9 9 9 (0)9 9 (0) 9 9 9 9 9 9) 0 0)
but getting this : application: not a procedure;
expected a procedure that can be applied to arguments
given: #<void>
arguments.:
#<void>
How fix it?
Please help me((
Assuming your indentation expresses what you want, this would be the working version of your code:
(define lab2
(lambda (currentList counter result)
(let countdown ((i (- (length currentList) 1)))
(if (= i 0)
(display result)
(begin
(if (pair? (list-ref currentList i)) ;1 if element is list
(if (> (+ 1 counter) result) ;1 if counter > currentResult
(begin
(set! counter (+ 1 counter))
(set! result (+ 1 result))
(countdown(- i 1))) ;2 then counter++, result++
(begin
(set! counter (+ 1 counter))
(countdown(- i 1)))) ;2 else counter++
(begin
(set! counter 0)
(countdown(- i 1))))))))) ;1 else counter=0
Lessons learned:
indent properly; especially don't put 2 consecutive forms on one single line
in an if form, if you need to use a begin form if you have more than one form in the then or else part and not double parentheses
if you use many beginwith if you should try and see if using cond instead of if wouldn't make your code more readable (left as an exercise to you)
if you have many set! forms you're probably not thinking the Scheme way; seriously, post another question where you explain what you want to do and a working version of this code!

Why does CLISP stops responding during this nested loop?

I am trying to create subsequences of some word with the following code. When I added by k, the code stopped responding, though if I replace k with a particular number, it works. What is happening?
(let ((c nil)) (loop for k from 0 to (length "abc")
finally (return c) do (loop for j from 0 to (length "abc") by k
do (loop for i from j to (length "abc") do (push (subseq "abc" j i) c)))))
Debugging
if I replace k with a particular number, it works
What happens if you replace k with 0?
It would be much more helpful if you formatted this code with typical conventions, and probably if you isolated the particular part of the code that's problematic. That is, (remove-duplicates …) isn't the problem here, you could have removed it. With some more conventional formatting, and some comments, your code is:
(remove-duplicates
(let ((c nil))
(loop for k from 0 to (length "abc") ; k starts at 0
finally (return c)
do (loop for j from 0 to (length "abc") by k ; looping for j from 0 to something by k
do (loop for i from j to (length "abc")
do (push (subseq "abc" j i) c)))))
:test 'equal)
What's going to happen if you try to loop for j from 0 to anything by k? You're pretty much saying, "start with j at 0, then increment it by 0 for the next iteration…" so j never gets anywhere. This really could have been caught with a print or format. I know that's not the same as using a debugger, but sometimes the simplest ways are the quickest:
[8]> (remove-duplicates
(let ((c nil))
(loop for k from 0 to (length "abc")
finally (return c)
do (loop for j from 0 to (length "abc") by k
do
(format t "~&k: ~a, j: ~a" k j )
(loop for i from j to (length "abc")
do (push (subseq "abc" j i) c)))))
:test 'equal)
k: 0, j: 0
k: 0, j: 0
k: 0, j: 0
…
Collecting subsequences
If you're trying to collect the subsequences of a given sequence, you might do it like this. This works on both strings (vectors) and lists (although it's less efficient for lists).
(defun subsequences (sequence)
(loop
with length = (length sequence)
for i from 0 to length
nconcing (loop
for j from (1+ i) to length
collecting (subseq sequence i j))))
(subsequences "abc")
;=> ("a" "ab" "abc" "b" "c")
(subsequences '(1 2 3))
;=> ((1) (1 2) (1 2 3) (2) (2 3) (3))
Appendex: A hard-to-understand error from SBCL
Interestingly, you'll get a runtime error with SBCL, although the error message doesn't make it particularly clear why. Perhaps it's related to the infinite looping.
* (remove-duplicates
(let ((c nil))
(loop for k from 0 to (length "abc")
finally (return c)
do (loop for j from 0 to (length "abc") by k
do
(loop for i from j to (length "abc")
do (push (subseq "abc" j i) c)))))
:test 'equal)
debugger invoked on a TYPE-ERROR in thread #<THREAD "initial thread" RUNNING
{1002978E71}>:
The value 0
is not of type
(OR (SINGLE-FLOAT (0.0)) (DOUBLE-FLOAT (0.0d0)) (RATIONAL (0))).
Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT] Exit debugger, returning to top level.
What do you think BY 0 should do in a loop?
(loop for i from 0 upto 10 by 0 do (princ '*))
If you are not advancing the variable, you'll get an endless loop.