UVa 10120 Gift?! in Common Lisp? - lisp

I'm learning common lisp I've been given a problem out of the uVA database (http://acm.uva.es/p/v101/10120.html) and a breadth search function (which takes in a start point, goal point and a legal move generator), i've got the theory down as to how i'm meant to get the answer but Lisp just isn't agreeing with me. Can i have some advice on how to proceed from this point onwards? Below is a link to the given problem and my two of my attempted solutions with lisp source code. Any help would be greatly appreciated! Thanks!
1.
(defun gift (N G)
(setq CR 9)
(setq i 3)
(cond ((= N G) "N and G equal")
((< N G) "Gift it on a rock outside limits")
((> N 49) "number of rocks is bigger than 49 - it will work")
((< N 9) "number of rocks is less than 9, it wont work")
((= N 0) "number of rocks is 0, it wont work")
((= G 0) "gift isn't on a rock, it wont work"))
(loop
(setq I (+ I 1))
(setq I (-(* I 2) 1))
(setq CR 9)
(breadth-search CR G #'lmg-moves)
(when (= CR G) (return "Let me Try!"))
(when (> CR N) (return "Don't laugh at me!"))
))
(defun lmg-moves (I)
(list (+ 9 I)
(- 9 I)
))
2.
(defvar *currentRock* 9)
(defvar *iterator* 3)
(defun gift (N G)
(setq *iterator* (+ *iterator* 1))
;; (breadth-search *currentRock* G #'LMG)
)
(defun LMG (a)
(+ a (-(* *iterator* 2) 1))
)
As can be seen above, the general idea is to simply apply a breadth-search function with the given legal move generator and hopefully, by analizing it's output we can determine whether we can reach the goal state or not. I will be glad to answer any questions if the code above is too confusing, thanks again!.

Among other potential issues:
You're using LOOP wrong. See PCL for info on loop. I've rehacked it a bit, but I don't know what you are attempting.
SETF is recommended over SETQ, as SETF is more general.
INCF increments a place by 1.
Your indentation is bad; if you fixed that you would notice that you're falling off the end of COND into the LOOP. I'd recommend an auto-indenting editor for using Lisp here. (Emacs is the standby).
(defun gift (N G)
(setq CR 9)
(setq i 3)
(cond ((= N G) "N and G equal")
((< N G) "Gift it on a rock outside limits")
((> N 49) "number of rocks is bigger than 49 - it will work")
((< N 9) "number of rocks is less than 9, it wont work")
((= N 0) "number of rocks is 0, it wont work")
((= G 0) "gift isn't on a rock, it wont work")) )
(loop
while t
do
(setq I (+ I 1))
(setq I (-(* I 2) 1))
(setq CR 9)
(breadth-search CR G #'lmg-moves)
(when (= CR G)
(return "Let me Try!"))
(when (> CR N)
(return "Don't laugh at me!"))))

There are some things that are immediately obvious:
You have exactly two legal return values, "Let me try!", and "Don't make fun of me!". You misspelt the first, rephrased the second, and added a lot of strings that do not have a use for the problem (are they meant as comments?).
The description calls the variables N and M, but your attempts take parameters N and G. Why confuse yourself? Either call them N and M, or (better) use meaningful names, like rock-number and gift-place.
Now, let's see your program structure.
(defun gift (N G)
(setq CR 9)
(setq i 3))
These setq instructions have undefined behaviour at this point, because CR and I are not defined yet. Many Lisp implementations will implicitly create globally special variables of these names, but it is bad style to depend on it. I have the impression that you want to use let here, like this:
(defun gift (rock-number gift-place)
(let ((current-rock 0)
(jump-number 0))
;; ...
))
Note that you should really start from the beginning, because you would miss the solution when the gift is on rock 1 or 4.
Next up, that cond form: it is dead code, because it has no side effects, and you throw away its return value immediately. It is thus at best a comment, and you should use a comment for that.
Finally, we have this funny loop:
(loop
(setq I (+ I 1))
(setq I (-(* I 2) 1))
(setq CR 9)
(breadth-search CR G #'lmg-moves)
(when (= CR G) (return "Let me Try!"))
(when (> CR N) (return "Don't laugh at me!"))))
I don't know what breadth-search does, but it seems that you really depend on the manipulation of globally special variables. I cannot say what might happen here. However, I can see several problems:
You can have up to two locations when jumping a certain distance from a given rock. It cannot be right to check only a single variable after each jump.
You seem to confuse the jump number with its jump distance. I goes in the sequence 1, 3, 7, 15 …, but the jump number sequence would be 1, 2, 3, 4 … while the jump distance sequence would be 1, 3, 5, 7 …. Even the rocks visited when always jumping right are a different sequence (1, 4, 9, 16 …).
You reset CR to 9 each time through the loop. I do not see how that could be right.
Stylistically, you should keep your variables as local as possible, using for example let, do, or the extended loop keywords :for and :with, then pass them into the functions that need them as arguments. This makes it much easier to reason about what is happening.
I think that your mental model of the solution algorithm is a bit confused. I would structure this in such a way that you loop over the jumps and keep a set of rocks that you can possibly be on after exactly this number of jumps. A special treatment for small N does not seem to really give a lot of efficiency gain. If you have a proof that N > 49 always has a solution, on the other hand, you should have a guard clause and a comment that outlines the proof.

Related

Questions about using recursive functions in lisp

I'm a beginner at lisp. I'm grateful that stackoverflow helped me a lot.
First, I want to express the recursive function using the lisp function.
There is no compilation error, but I want to check if the code I wrote is grammatically correct.
Below is the C code I wrote.
void queens(int i)
{
int j;
if (promising(i))
{
if (i == n)
{
//print all col list
return
}
else
{
for (j = 1; j <= n; j++)
{
col[i + 1] = j;
queens(i + 1);
}
}
}
}
Below is the lisp code.
(defvar n 4)
(defvar col (list 0 0 0 0 0 ))
(defun queens(i)
(let ((j 1))
(if (promising i)
(if (= i n) (print col)
(loop while (<= j n) do (setf (nth (+ 1 i ) col) j)
( queens (+ 1 i ) )
(incf j)))
)
))
First, you (still) need to fix the indentation, alignment, and general style. This is not merely to annoy you, but because it actually makes things clearer, and easier to debug. For example, if you do not indent properly, it becomes hard to see where each expression ends, and this is even worse when using complex macros such as loop. Your code, properly formatted but without any other modification, should be:
(defun queens (i)
(let ((j 1))
(if (promising i)
(if (= i n)
(print col)
(loop while (<= j n)
do (setf (nth (+ 1 i) col) j)
(queens (+ 1 i))
(incf j))))))
The closing parenthesis is placed right after the last form of the expression, without line break, without whitespace.
The opening parenthesis is also right before the first element of the form, without whitespace, but should be detached from what comes before, unless it is another parenthesis (so (defun queen (i) ...) is correct, while ( defun queens(i)) breaks two of the rules).
When using an if construct, either you write it all on a single line (the condition, the "then" form and the "else" form), or you have to insert line breaks after each of them. Otherwise, it is unclear when the "then" form ends and when the "else" starts.
When defining special variables with defvar, name them with '*' around their names, as in (defvar *n* 4) and (defvar *col* (list ...)).
Another style considerations, which helps with problems related to nesting: use when and unless instead of if if you are only interested in one of the two branches. This makes intent clear, and can also simplify the syntax in case of complex branches.
Now, for the code:
If you want to use loop, use the basic for constructs. Instead of writing
(loop while (< j n) do ... (incf j))
use
(loop for j from <start> to <end> do ...)
You can also use upto, below ... if you want subtly different termination conditions.
When you do this, you do not need to introduce a binding for j using let, it will be introduced by the loop.
If you want to modify a list, use a vector instead. Instead of defining col as (list ...), simply use (vector ...) or the make-array function. Afterwards, use elt or aref to access individual elements instead of nth which only works for lists. A version of the code which assumes that all the previous remarks have been taken into account:
(defun queens (i)
(when (promising i)
(if (= i n)
(print *col*)
(loop for j from 1 to *n*
do (setf (aref *col* (1+ i)) j)
(queens (1+ i))))))
Without knowing what promising does and what queens is supposed to do, it is hard to give more insight, but the algorithm is weird nonetheless. For example, in a given call to (queens i), the lexically apparent setf will only ever modify the i+1-th cell of col, setting it to a new j at each iteration. As far as I can tell, this simply results in (aref col (1+ i)) being set to n at the end of the loop. It also seems that you do not use the value recursively returned by queens (which is to be expected: your C function returns nothing !), and that you do not really do any check involving col, so a recursive solution seems weird, there is (seemingly) no relation between (queens i) and the (queens (1+ i)) that it calls n times in a loop !
If the above paragraph is irrelevant because promising also heavily modifies col: stop doing C-in-Lisp and stop modifying things all around the place. Don't rely on state, mutation, global variables & the like, when you can avoid it. It is easy to define recursive solution, to pass lists as arguments, to return several values ... and so it is generally unnecessary to use multiple functions, each of them calling the other ones, recursively modifying the shared global state. That's a mess and can't be debugged.

Number Partitioning in R5RS

I was asked in an internship interview to do a R5RS program that creates a function, let's say two-subsets. This function has to return #t if the list L contains two subsets with equal sums of elements and with equal numbers of elements, otherwise it returns #f. It takes in entry the list L (only positive numbers) and some parameters (that I judge useful. There is no conditions on the number of parameters) all equal to 0 at the beginning.
The requirements as I still remember were as follow:
- Do not define other functions and call them inside the "two-subsets" function.
- It can only use the following constructs: null?, cond, car, cdr, else, + ,=, not, and, #t, #f, two-subsets (itself for recursive call), the names of the parameters, such as list, sum, ...etc, numeric constants and parentheses.
There were some given examples on the results that we are supposed to have, let's say:
(two-subsets '(7 7) 0 0 0) returns #t. The two subsets are {7} and {7}.
(two-subsets '(7 7 1) 0 0) returns #t. The two subsets are {7} and {7}.
(two-subsets '(5 3 2 4) 0 0) returns #t. The two subsets are {2, 5} and {3, 4}.
(two-subsets '(1 2 3 6 9) 0 0) returns #f.
I started by writing the signature that it looks to me it should be something like this:
(define two-subsets (lambda (L m n ... other parameters)
(cond
The problem is really complicated and it's complexity is obviously more than O(n), I read on it on https://en.wikipedia.org/wiki/Partition_problem .
I tried to start by defining the algorithm first before coding it. I thought about taking as parameters: sum of the list L so in my conditions I'll iterate only on the combinations which sum is <= sum(L)/2. By doing that I can reduce a little bit the complexity of the problem, but still I couldn't figure out how to do it.
It looks like an interesting problem and I really want to know more about it.
Here is a version which does not depend on the numbers being all positive. I am reasonably sure that, by knowing they are, you can do much better than this.
Note this assumes that:
the partition does not need to be exhaustive;
but the sets must not be empty.
I'd be very interested to see a version which relies on the elements of the list being +ve!
(define (two-subsets? l sl sld ssd)
;; l is the list we want to partition
;; sl is how many elements we have eaten from it so far
;; sld is the length difference in the partitions
;; ssd is the sum difference in the partitions
(cond [(and (not (= sl 0))
(= sld 0)
(= ssd 0))
;; we have eaten some elements, the differences are zero
;; we are done.
#t]
[(null? l)
;; out of l, failed
#f]
;; this is where I am sure we could be clever about the set containing
;; only positive numbers, but I am too lazy to think
[(two-subsets? (cdr l)
(+ sl 1)
(+ sld 1)
(+ ssd (car l)))
;; the left-hand set worked
#t]
[(two-subsets? (cdr l)
(+ sl 1)
(- sld 1)
(- ssd (car l)))
;; the right-hand set worked
#t]
[else
;; finally drop the first element of l and try the others
(two-subsets? (cdr l) sl sld ssd)]))

Sum numbers that are positive which is less than n

(defun sum (n)
(if (n<0) 0 n-1) ;; if n<0, add 0. Else add the next smallest.
(sum (n-1)))
So far I come out with something like this but I am not sure how do I declare a variable to store the sum that I would like to return.
Note that you are implementing 1+2+...+m for m = n-1, which admits a simple formula:
(lambda (n)
;; You could inject n-1 on the formula to get n.(n-1)/2
;; (like in Vatine's answer), but here I just decrement
;; the input to show how to modify the local variable
;; and reuse the formula linked above to sum up-to m.
(decf n)
(if (minusp n)
0
(/ (* n (1+ n)) 2)))
An iterative version would work too, there is no need go recursive when doing simple loops:
(lambda (n) (loop :for x :below n :sum x))
Regarding your code:
Space matters1: n<0 is read as a symbol of name "N<0" (upcased by default). The same goes for n-1 which is a symbol named "N-1".
(n<0) will attempt to run the function named n<0. The same goes for (n-1).
Comparison: you can use (minusp n) or (< n 0).
Decrement: you can use (1- n) or (- n 1).
If what you wrote was correctly written, like this:
(defun sum (n)
(if (< n 0) 0 (- n 1))
(sum (- n 1)))
... there would still be issues:
You expect your (n-1) to actually decrement n but here the if only compute a value without doing side-effects.
You unconditionally call (sum (n-1)), which means: infinite recursion. The value returned by the preceding if is always ignored.
1: For details, look at constituent and terminating characters: 2.1.4 Character Syntax Types
Edit: zerop > minusp to check for negative numbers, fixed to fit OPs question
Was some time ago I used Lisp but if I recall right the last evaluation gets returned. A recursive solution to your problem would look like this:
(defun sum (n)
(if (<= n 0) 0 ;;if n is less or equal than 0 return 0
(+ (- n 1) (sum (- n 1))))) ;; else add (n-1) to sum of (n-1)
In Lisp, all comparator functions are just that, functions, so it needs to be (< n 0) and (- n 1) (or, more succinct, (1- n)).
You don't need to keep an intermediate value, you can simply add things up as you go. However, this is complicated by the fact that you are summing to "less than n", not "to n", so you need to use a helper function, if you want to do this recursively.
Even better, if you peruse the standard (easily available on-line, as the Common Lisp HyperSpec, you will sooner or later come across the chapter on iteration, where the loop facility does everything you want.
So if I needed to do this, I would do one of:
(defun my-sum (n)
(/ (* n (1- n)) 2))
or
(defun my-sum (n)
(loop for i below n
sum i))
If I absolutely needed to make it recursive, I would use something like:
(defun my-sum (n)
(labels ((sum-inner (i)
(if (< i 1)
0
(+ i (sum-inner (1- i))))))
(sum-inner (1- n))))
This is (almost) identical to defining a global function called sum-inner, which may be preferable for debugging purposes. However, since it is very unlikely that sum-inner would have any other use, I made it local.

if: Bad syntax error (Scheme programming)

(define generalized-triangular
(lambda (input n)
(if (= n 1)
1
(+ (input n) (generalized-triangular (- n 1))))))
This program is designed to take a number and a function as inputs and do the following..
f(1) + f(2) + f(3)+ … + f(N).
An example input would be:
(generalized-triangular square 3)
The Error message:
if: bad syntax;
has 4 parts after keyword in: (if (= n 1) 1 (+ (input n) (generalized-triangular (- n 1))) input)
The error is quite explicit - an if form can only have two parts after the condition - the consequent (if the condition is true) and the alternative (if the condition is false). Perhaps you meant this?
(if (= n 1)
1
(+ (input n) (generalized-triangular input (- n 1))))
I moved the input from the original code, it was in the wrong place, as the call to generalized-triangular expects two arguments, in the right order.
For the record: if you need to execute more than one expression in either the consequent or the alternative (which is not the case for your question, but it's useful to know about it), then you must pack them in a begin, for example:
(if <condition> ; condition
(begin ; consequent
<expression1>
<expression2>)
(begin ; alternative
<expression3>
<expression4>))
Alternatively, you could use a cond, which has an implicit begin:
(cond (<condition> ; condition
<expression1> ; consequent
<expression2>)
(else ; alternative
<expression3>
<expression4>))
Literal answer
The code you posted in your question is fine:
(define generalized-triangular
(lambda (input n)
(if (= n 1)
1
(+ (input n) (generalized-triangular (- n 1))))))
The error message in your question would be for something like this code:
(define generalized-triangular
(lambda (input n)
(if (= n 1)
1
(+ (input n) (generalized-triangular (- n 1)))
input)))
The problem is input. if is of the form (if <cond> <then> <else>). Not counting if itself, it has 3 parts. The code above supplies 4.
Real answer
Two tips:
Use DrRacket to write your code, and let it help you with the indenting. I couldn't make any sense of your original code. (Even after someone edited it for you, the indentation was a bit wonky making it still difficult to parse mentally.)
I don't know about your class, but for "real" Racket code I'd recommend using cond instead of if. Racket has an informal style guide that recommends this, too.
here's the tail-recursive
(define (generalized-triangular f n-max)
(let loop ((n 1) (sum 0))
(if (> n n-max)
0
(loop (+ n 1) (+ sum (f n))))))
Since you're using the racket tag, I assume the implementation of generalized-triangular is not required to use only standard Scheme. In that case, a very concise and efficient version (that doesn't use if at all) can be written with the racket language:
(define (generalized-triangular f n)
(for/sum ([i n]) (f (+ i 1))))
There are two things necessary to understand beyond standard Scheme to understand this definition that you can easily look up in the Racket Reference: how for/sum works and how a non-negative integer behaves when used as a sequence.

Is it correct to use the backtick / comma idiom inside a (loop ...)?

I have some code which collects points (consed integers) from a loop which looks something like this:
(loop
for x from 1 to 100
for y from 100 downto 1
collect `(,x . ,y))
My question is, is it correct to use `(,x . ,y) in this situation?
Edit: This sample is not about generating a table of 100x100 items, the code here just illustrate the use of two loop variables and the consing of their values. I have edited the loop to make this clear. The actual loop I use depends on several other functions (and is part of one itself) so it made more sense to replace the calls with literal integers and to pull the loop out of the function.
It would be much 'better' to just do (cons x y).
But to answer the question, there is nothing wrong with doing that :) (except making it a tad slower).
I think the answer here is resource utilization (following from This post)
for example in clisp:
[1]> (time
(progn
(loop
for x from 1 to 100000
for y from 1 to 100000 do
collect (cons x y))
()))
WARNING: LOOP: missing forms after DO: permitted by CLtL2, forbidden by ANSI
CL.
Real time: 0.469 sec.
Run time: 0.468 sec.
Space: 1609084 Bytes
GC: 1, GC time: 0.015 sec.
NIL
[2]> (time
(progn
(loop
for x from 1 to 100000
for y from 1 to 100000 do
collect `(,x . ,y)) ;`
()))
WARNING: LOOP: missing forms after DO: permitted by CLtL2, forbidden by ANSI
CL.
Real time: 0.969 sec.
Run time: 0.969 sec.
Space: 10409084 Bytes
GC: 15, GC time: 0.172 sec.
NIL
[3]>
dsm: there are a couple of odd things about your code here. Note that
(loop for x from 1 to 100000
for y from 1 to 100000 do
collect `(,x . ,y))
is equivalent to:
(loop for x from 1 to 100
collecting (cons x x))
which probably isn't quite what you intended. Note three things: First, the way you've written it, x and y have the same role. You probably meant to nest loops. Second, your do after the y is incorrect, as there is not lisp form following it. Thirdly, you're right that you could use the backtick approach here but it makes your code harder to read and not idiomatic for no gain, so best avoided.
Guessing at what you actually intended, you might do something like this (using loop):
(loop for x from 1 to 100 appending
(loop for y from 1 to 100 collecting (cons x y)))
If you don't like the loop macro (like Kyle), you can use another iteration construct like
(let ((list nil))
(dotimes (n 100) ;; 0 based count, you will have to add 1 to get 1 .. 100
(dotimes (m 100)
(push (cons n m) list)))
(nreverse list))
If you find yourself doing this sort of thing a lot, you should probably write a more general function for crossing lists, then pass it these lists of integers
If you really have a problem with iteration, not just loop, you can do this sort of thing recursively (but note, this isn't scheme, your implementation may not guaranteed TCO). The function "genint" shown by Kyle here is a variant of a common (but not standard) function iota. However, appending to the list is a bad idea. An equivalent implementation like this:
(defun iota (n &optional (start 0))
(let ((end (+ n start)))
(labels ((next (n)
(when (< n end)
(cons n (next (1+ n))))))
(next start))))
should be much more efficient, but still is not a tail call. Note I've set this up for the more usual 0-based, but given you an optional parameter to start at 1 or any other integer. Of course the above can be written something like:
(defun iota (n &optional (start 0))
(loop repeat n
for i from start collecting i))
Which has the advantage of not blowing the stack for large arguments. If your implementation supports tail call elimination, you can also avoid the recursion running out of place by doing something like this:
(defun iota (n &optional (start 0))
(labels ((next (i list)
(if (>= i (+ n start))
nil
(next (1+ i) (cons i list)))))
(next start nil)))
Hope that helps!
Why not just
(cons x y)
By the way, I tried to run your code in CLISP and it didn't work as expected. Since I'm not a big fan of the loop macro here's how you might accomplish the same thing recursively:
(defun genint (stop)
(if (= stop 1) '(1)
(append (genint (- stop 1)) (list stop))))
(defun genpairs (x y)
(let ((row (mapcar #'(lambda (y)
(cons x y))
(genint y))))
(if (= x 0) row
(append (genpairs (- x 1) y)
row))))
(genpairs 100 100)