Nested for-loop in LispWorks (4x4 queens) - for-loop

I have just started using LispWorks and I am working on the 4x4 Queen problem. What I am trying to do is with the help of 4 for-loops state all the possible Queen-combinations, and then checking whether they are possible solutions or not. A possible state (1 3 4 2) for example means that in row 1 queen is in column 1, in row 2 queen is in column 3 and so on.
I think I am doing something wrong though because the compiler don't like my loops. The error I'm getting is something like: Loop keyword expected in...
Here is the code:
(loop for i in '(1 2 3 4)
nconc (loop for j in '(1 2 3 4)
nconc (loop for k in '(1 2 3 4)
nconc (loop for l in '(1 2 3 4)
(defvar first 0)
(defvar second 0)
(defvar third 0)
(defvar fourth 0)
(setq first (abs (- 1 i)))
(setq second (abs (- 2 j)))
(setq third (abs (- 3 k)))
(setq fourth (abs (- 4 l)))
(if (and (not (eq first second)) (not (eq first third)) (not (eq first fourth)) (not (eq second third))
(not (eq second fourth)) (not (eq first second)) (not (eq third fourth)))
(if (and (or (eq i j) (eq i k) (eq i l) (eq j k) (eq j l)) (or (eq k l)))
(print i j k l)))))))
Please help me out with the nested loops and feel free to comment on my code and possibly suggest better ways of solving this problem. Please keep it fairly basic, I am a complete beginner to LispWorks and I have only done some ADA 95 and Java before.
Thank you in advance

The reason you get the error message is that your code is lacking the keyword do after '(1 2 3 4) in the inner loop. As you are not collecting results from the loops, just printing the final result, you should use do instead of nconc in the outer loops as well.
Fixing this, another error shows up: print only print one object, so in order to print all four numbers you can use e.g. (print (list i j k l))
The program then prints
(1 1 1 1)
(1 3 1 1)
(2 2 1 1)
(4 2 2 2)
(4 4 3 3)
(4 4 4 4)
so something is wrong with the logic as well.
However, there are also lots of improvements that can be done to the code:
Do not use defvar to introduce new variables inside the loop. defvar creates dynamic ("global") variables. Instead, use let, or introduce them as loop variables, like you have done with i , j etc.
Instead of first creating the variables, and then updating them once using setq, give them the correct value when they are created (using let or a loop keyvword).
As you are comparing pairs of numbers: Instead of using eq (which is for symbols) or eql (which is the correct one for comparing two numbers of the same type), use = or /= which can compare many numbers to check if they are all equal/different.
Together with a small fix of the logic, this results in the following code (which for illustration introduces some variables using loop keywords, and some using let):
(loop for i in '(1 2 3 4)
for first = (abs (- 1 i))
do (loop for j in '(1 2 3 4)
for second = (abs (- 2 j))
do (loop for k in '(1 2 3 4)
do (loop for l in '(1 2 3 4)
do (let ((third (abs (- 3 k)))
(fourth (abs (- 4 l))))
(if (and (/= first second third fourth)
(/= i j k l))
(print (list i j k l))))))))
Which result in
(2 4 3 1)
(3 2 4 1)
(4 1 3 2)
(4 2 1 3)
meaning that there are still logic errors present.
Hopefully the simplified code makes it easy to spot the error, which probably has something to do with not comparing (+ i 1), (+ j 2) etc.
Finally: If you want to extend the code to handle more queens, creating a recursive solution will be better than a solution using even more nested loops.

Related

Scheme - Adding a list to a list of lists?

I am trying to answer a scheme question, for a part of this question I have to make a list of lists:
(define (join a b (result '()))
(cons (list a b) result))
So I am taking in two characters, and placing them in a list, then I need to place each sublist into a list of lists, this function is being called recursively with two characters each time, so it is supposed to work like this:
join 1 4
=> ((1 4))
join 2 5
=> ((1 4) (2 5))
join 3 6
=> ((1 4) (2 5) (3 6))
However, I am getting ((3 6) (2 5) (1 4)), so the elements need to be reversed, I tried reversing my cons function to (cons result (list a b)) but then I get (((() 1 4) 2 5) 3 6), how can I get the list the right way around, or is there an easier way to do what I'm doing?
If you need to add elements at the end of a list use append; cons is for adding elements at the head. Try this:
(define (join a b (result '()))
(append result (list (list a b))))
Notice that append combines two lists, that's why we have to surround the new element inside its own list. Also, it's not a good idea to add elements at the end, using append is more expensive than using cons - if possible, rethink your algorithm to add elements at the head, and reverse the result at the end.
This can easily be done like this:
(define (group-by-2 lst)
(let loop ((lst lst) (rlst '()))
(if (or (null? lst) (null? (cdr lst)))
(rcons->cons rlst)
(loop (cdr lst)
(rcons (list (car lst)
(cadr lst))
rlst)))))
(group-by-2 '(1 2 3 4 5 6 7 8))
; ==> ((1 2) (2 3) (3 4) (4 5) (5 6) (6 7) (7 8))
Now rcons is like cons but it makes a reverse list. (rcons 1 (rcons 2 (rcons 3))) ; ==> {3 2 1} however it is not a list so you have to convert it to a list (rcons->list (rcons 1 (rcons 2 (rcons 3))) ; ==> (3 2 1)
The magic functions are really not that magical:
(define rcons cons)
(define rcons->cons reverse)
So in fact I didn't really have to make that abstraction, but hopefully I made my point. It doesn't matter how you organize the intermediate data structure in your programs so why not make the best for the job you are doing. For lists it's always best to iterate from beginning to end and make from end to beginning. Every insert O(1) per element and you do a O(n) reverse in the end. It beats doing append n times that would make it O(n²)

Reversing a simple function in a "creative" way in racket

I need some help :D.
I have written this procedure that turns a string into a list of numbers:
(define (string->encodeable string)
(map convert-to-base-four (map string->int (explode string))))
I need a function that does the exact opposite. In other words, takes a list of a list of numbers in base 4, turn it into base 10, and then creates a string. Is there a "creative" way to reverse my function or do I have to write every opposite step again. Thank you so much for your help.
A standard Scheme implementation using SRFI-1 List library
#!r6rs
(import (rnrs base)
(only (srfi :1) fold))
(define (base4-list->number b4l)
(fold (lambda (digit acc)
(+ digit (* acc 4)))
0
b4l))
(base4-list->number '(1 2 3))
; ==> 27
It works the same in #lang racket but then you (require srfi/1)
PS: I'm not entirely sure if your conversion from base 10 to base 4 is the best solution. Imagine the number 95 which should turn into (1 1 3 3). I would have done it with unfold-right in SRFI-1.
Depends on how you define "creative". In Racket you could do something like this:
(define (f lst)
(number->string
(for/fold ([r 0]) ([i (in-list lst)])
(+ i (* r 4)))))
then
> (f '(1 0 0))
"16"
> (f '(1 3 2 0 2 1 0 0 0))
"123456"
The relationship you're looking for is called an isomorphism
The other answers here demonstrate this using folds but at your level I think you should be doing this on your own – or at least until you're more familiar with the language
#lang racket
(define (base10 ns)
(let loop ((ns ns) (acc 0))
(if (empty? ns)
acc
(loop (cdr ns) (+ (car ns)
(* 4 acc))))))
(displayln (base10 '(3 0))) ; 12
(displayln (base10 '(3 1))) ; 13
(displayln (base10 '(3 2))) ; 14
(displayln (base10 '(3 3))) ; 15
(displayln (base10 '(1 0 0))) ; 16
(displayln (base10 '(1 3 2 0 2 1 0 0 0))) ; 123456
#naomik's answer mentioned isomorphisms. When you construct an isomorphism, you're constructing a function and its inverse together. By composing and joining isomorphisms together, you can construct both directions "at once."
;; Converts between a base 4 list of digits (least significant first, most
;; significant last) and a number.
(define iso-base4->number
(iso-lazy
(iso-cond
;; an iso-cond clause has an A-side question, an A-to-B isomorphism,
;; and a B-side question. Here the A-side is empty and the B-side is
;; zero.
[empty? (iso-const '() 0) zero?]
;; Here the A-side is a cons, and the B-side is a positive number.
[cons?
(iso-join
cons
(λ (r q) (+ (* 4 q) r))
[first iso-identity (curryr remainder 4)]
[rest iso-base4->number (curryr quotient 4)])
positive?])))
This code contains all the information needed to convert a base 4 list into a number and back again. (The base 4 lists here are ordered from least-significant digit to most-significant digit. This is reversed from the normal direction, but that's okay, that can be fixed outside.)
The first cond case maps empty to zero and back again.
The second cond case maps (cons r q) to (+ (* 4 q) r) and back again, but with q converted between lists and numbers recursively.
Just as a cons cell can be split using first and rest, a positivive number can be split into its "remainder-wrt-4" and its "quotient-wrt-4". Since the remainder is a fixed size and the quotient is an arbitrary size, the remainder is analogous to first and the quotient is analogous to rest.
The first and remainder don't need to be converted into each other, so the first iso-join clause uses iso-identity, the isomorphism that does nothing.
[first iso-identity (curryr remainder 4)]
The rest and quotient do need to be converted though. The rest is a list of base 4 digits in least-to-most-significant order, and the quotient is the number corresponding to it. The conversion between them is iso-base4->number.
[rest iso-base4->number (curryr quotient 4)]
If you're interested in how these isomorphism forms like iso-const, iso-cond, and iso-join are defined, this gist contains everything needed for this example.

Define a scheme function that computes the trace of a square matrix

Example
(trace '((1 2 3) (4 5 6) (7 8 9))) should evaluate to 15 (1+5+9).
Hint: use map to obtain the smaller matrix on which trace can be applied recursively. The Matrix should be squared.
i tried to do it but i cant seem to do it, i tried to get the diagonals first.
define (diagonals m n)
(append
(for/list ([slice (in-range 1 (- (* 2 n) 2))])
(let ((z (if (< slice n) 0 (add1 (- slice n)))))
(for/list ([j (in-range z (add1 (- slice z)))])
(vector-ref (vector-ref m (sub1 (- n j))) (- slice j))))
is there any way to solve that question in a very simple recursive way using map.
i tried to solve it like that.
define (nth n l)
(if (or (> n (length l)) (< n 0))
(if (eq? n 0) (car l)
(nth (- n 1) (cdr l)))))
(+ (nth 3 '(3 4 5)) (nth 2 '(3 4 5)) (nth 3 '(3 4 5)))
but it didnt work too.
Although I don't think answering homework questions is a good idea in general, I can't resist this because it is an example of both what is so beautiful about Lisp programs and what can be so horrible.
What is so beautiful:
the recursive algorithm is almost identical to a mathematical proof by induction and it's just so pretty and clever;
What is so horrible:
matrices are not semantically nested lists and it's just this terrible pun to pretend they are (I'm not sure if my use of first & rest makes it better or worse);
it just conses like mad for no good reason at all;
I'm pretty sure its time complexity is n^2 when it could be n.
Of course Lisp programs do not have to be horrible in this way.
To compute the trace of a matrix:
if the matrix is null, then the trace is 0;
otherwise add the top left element to the trace of the matrix you get by removing the first row and column.
Or:
(define (awful-trace m)
(if (null? m)
;; the trace of the null matrix is 0
0
;; otherwise the trace is the top left element added to ...
(+ (first (first m))
;; the trace of the matrix without its first row and column which
;; we get by mapping rest over the rest of the matrix
(awful-trace (map rest (rest m))))))
And you may be tempted to think the following function is better, but it is just as awful in all the ways described above, while being harder to read for anyone not versed in the auxiliary-tail-recursive-function-with-an-accumulator trick:
(define (awful-trace/not-actually-better m)
(define (awful-loop mm tr)
(if (null? mm)
tr
(awful-loop (map rest (rest mm))
(+ tr (first (first mm))))))
(awful-loop m 0))
Try:
(apply + (map (lambda (index row) (list-ref row index))
'(0 1 2)
'((1 2 3) (4 5 6) (7 8 9))))
Of course, turn that into a function.
To handle matrices larger than 3x3, we need more indices.
Since map stops when it traverses the shortest of the lists, the (0 1 2) list can just be padded out by hand as large as ... your best guess at the the largest matrix you think you would ever represent with nested lists in Scheme before you graduate and never see this stuff again.

How to use double do loop in Scheme?

I want to use "do" command to show(1 1)(1 2)(1 3)(2 1)(2 2)(2 3)(3 1)(3 2)(3 3)
and my code is below:
(lambda ( )
(define a 1)
(define b 1)
(do ((a 1 (+ a 1))) (= a 3)
(do ((b 1 (+ b 1))) (= b 3)
(display a b)
)))
But this only show3as the result. Did I do something wrong? How should I correct it?
To Michael Vehrs,
Thank a lot, it really works! But I'm still confusing about the exit condition. I tried to change the>in your code to=and it shows(1 1)(1 2)(2 1)(2 2). Is it because it stops when a = 3 so it won't print?
So "list" command can combine several variables. But how about "newline" command? I tried to remove it and it just add another () in the last.
Thank you for the answer. I'm a new Scheme learner trying to use it on TracePro. Do you have any tip(book, Youtube video, website) for me about learning Scheme? Any advise would help.
A do loop is just syntax sugar for a recursive function. You might as well get used to write it directly. Here is a way to do it with one named let with two variables and an accumulator.
(let loop ((a 3) (b 3) (acc '()))
(cond ((zero? a) acc) ; finished
((zero? b) (loop (sub1 a) 3 acc)) ; b finsihed, reduce a and reset b
(else (loop a (sub1 b) (cons (list a b) acc))))) ; reduce b and add to front of acc
; ==> ((1 1) (1 2) (1 3) (2 1) (2 2) (2 3) (3 1) (3 2) (3 3))
Notice this makes the result in reverse order so it's optimal for lists that always are created in reverse order since that only can add new element in front.
You mean:
(lambda ()
(do ((a 1 (+ a 1)))
((> a 3) (newline))
(do ((b 1 (+ b 1)))
((> b 3))
(display (list a b))))))
Your code has a number of problems: The exit condition for the do loop is incorrect (and makes your procedure return 3). display takes a single object and an optional port as arguments. Defining your variables a and b is unnecessary, since the do construct defines new loop variables anyway.

Add successive integers with recursive tests (conditionals)

My recursive function correctly sums all the integers, inclusively, between a and b. However, when I swap my arguments, the result is incorrect. I am reading SICP. My code is (scheme):
(define (sum-integers a b)
(if (> a b)
(if (= (- a 1) b)
(+ a b)
(+ a(sum-integers (- a 1) b)))
(+ a (sum-integers (+ a 1) b))))
(sum-integers 5 2)
(sum-integers 2 5)
I'm sure my compiler is applicative order,so I think the output should be the same.
(sum-integers 5 2)
(sum-integers 2 5)
In fact,
(sum-integers 5 2) ==> 14
(sum-integers 2 5) ==> 25
But 2+3+4+5 = 5+4+3+2 = 14.
Why are my results different?
In your second test case, which displays the bug, your loop doesn't terminate until a = 6 and b = 5. Then it adds an extra 6 and 5 to the total of 14, to get 25.
The reason you found this bug tricky to find may be because the code was more complex than it could be, or because you haven't yet learned how to trace recursive code.
I also noticed that your code indentation is not consistent. Let your editor indent your code for you, to help you follow the logic.
I have written up the code for the design #alfasin mentioned in the comments. You can see the simplicity makes it easier to debug. If a > b then we just swap the arguments and carry on as before.
I think the key to thinking about this is to make sure that the operation that you want to repeat (here it is addition) appears only once in your function.
(define (sum2-integers a b)
(if (> a b)
(sum2-integers b a) ; if the wrong way round, swap them
(if (= a b) ; termination condition
b
(+ a (sum2-integers (+ a 1) b)))))
> (sum2-integers 5 2)
14
> (sum2-integers 2 5)
14
One step further towards simplicity. I find that the multi-way conditional branch cond is much more readable than nested ifs, as there are really three branches in this code.
(define (sum3-integers a b)
(cond [(> a b) (sum3-integers b a)]
[(= a b) b]
[else (+ a (sum3-integers (+ a 1) b))]))
The condition if (> a b) creates a different flow when you send 5,2 vs. 2,5:
When you send a=5,b=2 it means that a > b so we'll get into the if, and since 5-1 > 2 the recursive call will be to (+ a(sum-integers (- a 1) b)).
When you send a=2, b=5 the condition if (> a b) will return false and the recursive call will be the last line: (+ a (sum-integers (+ a 1) b))
As you can see:
(+ a (sum-integers (- a 1) b)) is not the same as:
(+ a (sum-integers (+ a 1) b))
so no wonder you're getting different results.

Resources