I've written my first ever Common Lisp function and I'm having trouble tracking down where my error is being produced. How do I trouble shoot the following error:
Error: Stack overflow on value stack. While executing: TRUNCATE
Here is my code:
(defun mergelist (alist low mid high)
(setq i1 low)
(setq i2 (+ mid 1))
(setq i low)
(setq blist `())
(loop while (and (<= i1 mid) (<= i2 high)) do
(if (<= (nth i1 alist) (nth i2 alist))
(setf (nth (+ i 1) blist) (nth (+ i1 1) alist))
(setf (nth (+ i 1) blist) (nth (+ i2 1) alist))
)
)
(loop while (<= i1 mid) do
(setf (nth (+ i 1) blist) (nth (+ i1 1) alist))
)
(loop while (<= i2 high) do
(setf (nth (+ i 1) blist) (nth (+ i2 1) alist))
)
(setq j low)
(loop for j from j to high do
(setf (nth i alist) (nth i blist))
)
)
(defun mergesort (alist low high)
(when (< low high)
(mergesort alist low (/ (+ low high) 2))
(mergesort alist (/ (+ low high) (+ 2 1)) high)
(mergelist alist low (/ (+ low high) 2) high)
)
)
The following is how I'm testing the function:
(setq dlist `(5 1 4 2 3))
(mergesort dlist 0 4)
My expected return is:
(1 2 3 4 5)
There are quite a few things we can do to improve this code.
1. Indenting
Lisp has relatively little syntax, but we use indenting to help highlight the structure of the code. Most Lisp aware editors help manage that. The most obvious departure from the conventional indenting approach is closing parentheses on following lines. I've Indented the mergelist function to show a more readable function body - well, at least to me.
(defun mergelist (alist low mid high)
(setq i1 low)
(setq i2 (+ mid 1))
(setq i low)
(setq blist `())
(loop while (and (<= i1 mid) (<= i2 high)) do
(if (<= (nth i1 alist) (nth i2 alist))
(setf (nth (+ i 1) blist) (nth (+ i1 1) alist))
(setf (nth (+ i 1) blist) (nth (+ i2 1) alist))))
(loop while (<= i1 mid) do
(setf (nth (+ i 1) blist) (nth (+ i1 1) alist)))
(loop while (<= i2 high) do
(setf (nth (+ i 1) blist) (nth (+ i2 1) alist)))
(setq j low)
(loop for j from j to high do
(setf (nth i alist) (nth i blist))))
2. Setq's, setf's vs Let.
The code above creates variables in the top level environment by setq'ing them ( unless of course, you have defparametered them elsewhere). This can have some undesirable side effects as programs get larger ( what if two functions use "i" at the same time?) . Its better to use LET to create local lexical variables so something like
(defun mergelist-2 (alist low mid high)
(let ((i1 low)
(i2 (+ mid 1)
i (low)
blist '()))
(loop while (and (<= i1 mid) (<= i2 high)) do
(if (<= (nth i1 alist) (nth i2 alist))
(setf (nth (+ i 1) blist) (nth (+ i1 1) alist))
(setf (nth (+ i 1) blist) (nth (+ i2 1) alist))))
(loop while (<= i1 mid) do
(setf (nth (+ i 1) blist) (nth (+ i1 1) alist)))
(loop while (<= i2 high) do
(setf (nth (+ i 1) blist) (nth (+ i2 1) alist)))
(setq j low)
(loop for j from j to high do
(setf (nth i alist) (nth i blist))) ))
3. Forms can return values
A lisp form often returns a value. If we type in (+ 1 2) at the repl we will see 3. A defun will normally return a value usually as the last form in its body.
If we look at mergelist we see that it is not explicility returning any value but is instead trying to use the variable alist to communicate the return values. This does not work!
Lisp provides the trace facility which lets us understand what is going on inside
This is the first 16 lines of trace. My system craps out at line 600
0: (MERGESORT (5 1 4 2 3) 0 4)
1: (MERGESORT (5 1 4 2 3) 0 2)
2: (MERGESORT (5 1 4 2 3) 0 1)
3: (MERGESORT (5 1 4 2 3) 0 1/2)
4: (MERGESORT (5 1 4 2 3) 0 1/4)
5: (MERGESORT (5 1 4 2 3) 0 1/8)
6: (MERGESORT (5 1 4 2 3) 0 1/16)
7: (MERGESORT (5 1 4 2 3) 0 1/32)
8: (MERGESORT (5 1 4 2 3) 0 1/64)
9: (MERGESORT (5 1 4 2 3) 0 1/128)
10: (MERGESORT (5 1 4 2 3) 0 1/256)
11: (MERGESORT (5 1 4 2 3) 0 1/512)
12: (MERGESORT (5 1 4 2 3) 0 1/1024)
13: (MERGESORT (5 1 4 2 3) 0 1/2048)
14: (MERGESORT (5 1 4 2 3) 0 1/4096)
15: (MERGESORT (5 1 4 2 3) 0 1/8192)
16: (MERGESORT (5 1 4 2 3) 0 1/16384)
at line 600 you see
600: (MERGESORT (5 1 4 2 3) 0
1/1037378892220248239628101965922790287753111558060609224998914332422663202853227036599926762236775948572049471652825197295598787768852943826971718708528490921765295450850377380921344)
This is a very small number and explains the error message about truncate.
You can see that the alist array is not changing as we proceed down the call stack. Thats because the alist function parameter is local to each invocation of mergelist.
What we need to do is have mergelist return a value explicility each time its called.
(defun mergelist-3 (alist low mid high)
(let ((i1 low)
(i2 (+ mid 1)
i (low)
j
blist '()))
(loop while (and (<= i1 mid) (<= i2 high)) do
(if (<= (nth i1 alist) (nth i2 alist))
(setf (nth (+ i 1) blist) (nth (+ i1 1) alist))
(setf (nth (+ i 1) blist) (nth (+ i2 1) alist))))
(loop while (<= i1 mid) do
(setf (nth (+ i 1) blist) (nth (+ i1 1) alist)))
(loop while (<= i2 high) do
(setf (nth (+ i 1) blist) (nth (+ i2 1) alist)))
(setq j low)
(loop for j from j to high do
(setf (nth i alist) (nth i blist)))
*;return value here*
))
As a further hint , the last loop in the function is not needed.
Additionally, you will have to capture that return value in mergesort and have mergesort return an explicit value as well.
I would also recommend that you read a bit about the loop macro - google for "Practical Common Lisp Loop for Black belts" which will help you grasp the syntax and the sort of things you can do with loop.
Now, there are still a few things to fix in the code but I hope I've given you enough to get through this iteration
There is too much wrong with the code:
treats lists as vectors: if you want a Lisp data structure with random access, then use a vector. Not a list.
doesn't declare variables
while loops don't work at all
imperative, instead of functional
wrong code layout
Best to start from scratch and to avoid above mistakes. If you want Lisp lists, then use a different way to write a mergesort. Hint: lists are not like vectors. They might be used like that, but usually it's a mistake to do so.
Related
So currently, I wrote a Clojure code to do Trapezoidal integration of a polynomial function in HackerRank.com:
https://www.hackerrank.com/challenges/area-under-curves-and-volume-of-revolving-a-curv
(defn abs[x]
(max x (- 0 x))
)
(defn exp[x n]
(if (> n 0)
(* x (exp x (- n 1)))
1
)
)
(defn fact[x]
(if (> x 0)
(* x (fact (- x 1)))
1)
)
(defn func[x lst1 lst2]
((fn step [sum lst1 lst2]
(if (> (.size lst1) 0)
(step (+ sum (* (last lst1) (exp x (last lst2)))) (drop-last lst1) (drop-last lst2))
sum
)
)
0 lst1 lst2
)
)
(defn integrate[f a b]
(def h 0.001)
(def n (/ (abs (- b a)) h))
((fn step[i sum]
(if (< i n)
(step (+ i 1) (+ sum (f (+ (* i h) a))))
(* h (+ (/(+ (f a) (f b)) 2) sum))
)
) 0 0)
)
(defn volumeIntegral[f a b]
(defn area[r]
(* 3.14159265359 (* r r)))
(def h 0.001)
(def n (/ (abs (- b a)) h))
((fn step[i sum]
(if (< i n)
(step (+ i 1) (+ sum (area (f (+ (* i h) a)))))
(* h (+ (/ (+ (f a) (f b)) 2) sum))
)
) 0 0)
)
(defn lineToVec[line_str] (clojure.string/split line_str #"\s+"))
(defn strToDouble [x] (Double/parseDouble (apply str (filter #(Character/isDigit %) x))))
(defn readline[vec]
((fn step[list vec]
(if (> (.size vec) 0)
(step (conj list (last vec)) (drop-last vec))
list
)
) '() vec)
)
(integrate (fn [x] (func x '(1 2 3 4 5 6 7 8) '(-1 -2 -3 -4 1 2 3 4))) 1 2)
(volumeIntegral (fn [x] (func x '(1 2 3 4 5 6 7 8) '(-1 -2 -3 -4 1 2 3 4))) 1 2)
However, the output I have is:
107.38602491666647
45611.95754801859
While is supposed to be around:
101.4
41193.0
My code passed the first two test cases, but didn't manage to pass the rest. I assume is because of the issue accuracy. I looked through my code several times but couldn't seem to make it better. What am I doing wrong here ? Thank you.
Your exp function isn't quite right -- it doesn't handle negative exponents correctly. Probably best just to use Math/pow.
The other thing you could do is adjust your h value in volumeIntegral but to avoid stack issues, use recur (which gives you tail recursion), e.g. here's a slightly modified version:
(defn volume-integral [f a b]
(defn area[r]
(* Math/PI (* r r)))
(def h 0.000001)
(def n (/ (abs (- b a)) h))
((fn [i sum]
(if (not (< i n))
(* h (+ (/ (+ (f a) (f b)) 2) sum))
(recur (+ i 1) (+ sum (area (f (+ (* i h) a)))))))
0 0))
(I did the something similar with integral.) All in all, I wasn't able to quite hit the second figure, but this should get you on the right track:
101.33517384995224
41119.11576557253
I have two dolists. The first dolist has a variable i and the inner dolist has a variable j.
I want to make a final list li look like ((00)(01)(10)(11))
(setq mm '(0 1))
(setq li '())
(dolist (i mm)
(dolist (j mm)
(progn
(setq ans (cons ans (list (nth i mm)
(nth j mm)))))))
gives me
((((NIL 0 0) 0 1) 1 0) 1 1)
CL-USER 68 > (let ((ans ()))
(dolist (i mm (reverse ans))
(dolist (j mm)
(setq ans (cons (list (nth i mm)
(nth j mm))
ans)))))
((0 0) (0 1) (1 0) (1 1))
Got it.
The keyword "List" does the trick.
(dolist (i mm) (dolist(j mm) (progn (setq ans (append ans (list(list(nth i mm )(nth j mm))))))))
When reaching my recursion cases, I use list to append the future result with the current one, but I end up with a nested list because of recursion. This causes an error when I have a number that causes recursion for more than five times.
Any ideas how I can get results in a single plain non-nested list, e.g.:
CL-USER 100 : 8 > (BINARY_LIST 4)
(1 0 0)
Code & Example output:
CL-USER 99 : 8 > (defun binary_list (i)
(COND
((= i 0) 0)
((= i 1) 1)
((= (mod i 2) 0) (list (binary_list (truncate i 2)) 0))
(t (list (binary_list (truncate i 2)) 1))
)
)
BINARY_LIST
CL-USER 100 : 8 > (BINARY_LIST 4)
((1 0) 0)
CL-USER 101 : 8 > (BINARY_LIST 104)
((((# 1) 0) 0) 0)
You are almost there. All you need to do is to replace list with nconc:
(defun binary-list (n)
(cond ((= n 0) (list 0))
((= n 1) (list 1))
(t (nconc (binary-list (truncate n 2)) (list (mod n 2))))))
You can avoid calling both truncate and mod by collecting both values in integer division:
(defun binary-list (n)
(assert (>= n 0))
(multiple-value-bind (q r) (floor n 2)
(if (zerop q)
(list r)
(nconc (binary-list q) (list r)))))
Note that this algorithm is quadratic because nconc has to traverse the result on each iteration. This can be avoided by passing an accumulator:
(defun binary-list (n &optional acc)
(assert (>= n 0))
(multiple-value-bind (q r) (floor n 2)
(if (zerop q)
(cons r acc)
(binary-list q (cons r acc)))))
Now we have a tail-recursive function which can be compiled to iteration by a modern compiler.
One more optimization trick you could use (which, in fact, should be done by the compiler - try disassemble to check!) is using ash and logand instead of the much more general and expensive floor:
(defun binary-list (n &optional acc)
(cond ((zerop n) (or acc (list 0)))
((plusp n)
(binary-list (ash n -1) (cons (logand 1 n) acc)))
(t (error "~S: non-negative argument required, got ~s" 'binary-list n))))
Incidentally, lispers usually use dash instead of underscores in symbols, so your binary_list should be binary-list if you do not want to offend our tender aesthetics.
this seems to me to be the most direct, least roundabout manner to achieve the desired results every time:
(defun mvp-binary-from-decimal (n r)
(if (zerop n)
r
(multiple-value-bind (a b)
(floor n 2)
(mvp-binary-from-decimal a (cons b r)))))
(defun binary-from-decimal (n)
(if (and (numberp n) (plusp n))
(mvp-binary-from-decimal n '())
(if (eql n 0) '(0) nil)))
tested in slime, sbcl, clisp - used as follows:
CL-USER> (binary-from-decimal 100)
(1 1 0 0 1 0 0)
CL-USER> (binary-from-decimal 10)
(1 0 1 0)
CL-USER> (binary-from-decimal 0)
(0)
there are some advanced reasons as to why this might be the most desirable manner in which to implement such functionality, but for now, suffice to say that it is clean, polite, readable and always works.
I have 2 numbers let's say number1=5 and number2=3 and I want to create a list in this form
((1(1 2 3)) (2(1 2 3)) (3(1 2 3)) (4(1 2 3)) (5(1 2 3)))
So the number1 indicates the number of the elements in the list and number2 indicates the total elements that will be as the second part of every element..
I have smth like this untill now
(define mylist '())
(define (pushlist item item2)
(do ((j 1 (+ j 1))) ((> j item2))
(set! mylist(list mylist (list item j)))))
(define (createlist number number2)
(do ((j 1 (+ j 1))) ((> j number))
(pushlist j number2)
))
(createlist 5 3)
Unfortunately it doesn't work.. It doesn't give the result I want.. It gives me this (((((((((((((((() (1 1)) (1 2)) (1 3)) (2 1)) (2 2)) (2 3)) (3 1)) (3 2)) (3 3)) (4 1)) (4 2)) (4 3)) (5 1)) (5 2)) (5 3))
There are many ways to solve this problem - for example, using explicit recursion, or using higher-order procedures. Your approach is not recommended, in Scheme you should try to avoid thinking about loops and mutation operations. Although it is possible to write such a solution, it won't be idiomatic. I'll try to explain how to write a more idiomatic solution, using explicit recursion first:
; create a list from i to n
(define (makelist i n)
(if (> i n)
'()
(cons i (makelist (add1 i) n))))
; create a list from i to m, together with
; a list returned by makelist from 1 to n
(define (makenumlist i m n)
(if (> i m)
'()
(cons (list i (makelist 1 n))
(makenumlist (add1 i) m n))))
; call previous functions
(define (createlist number1 number2)
(makenumlist 1 number1 number2))
Now, an even more idiomatic solution would be to use higher-order procedures. This will work in Racket:
; create a list from i to n
(define (makelist n)
(build-list n add1))
; create a list from i to m, together with
; a list returned by makelist from 1 to n
(define (makenumlist m n)
(build-list m
(lambda (i)
(list (add1 i) (makelist n)))))
; call previous functions
(define (createlist number1 number2)
(makenumlist number1 number2))
See how we can avoid explicit looping? that's the Scheme way of thinking, the way you're expected to solve problems - embrace it!
I don't think that your pushlist procedure is doing what you you expect it to.
(define (pushlist item item2)
(do ((j 1 (+ j 1)))
((> j item2))
(set! mylist (list mylist (list item j)))))
If you have a list (x y z) and you want to push a new value v into it, you'd do
(set! lst (cons v lst))
because (cons v (x y z)) == (v x y z). By doing
(set! mylist (list mylist (list item j)))
you're making mylist always have exactly two elements, where the first is a deeper and deeper nested list. Óscar López's answer gives a more idiomatic approach to this problem. Here's a similar idiomatic approach:
(define (range n)
; returns a list (1 ... n)
(let rng ((n n) (l '()))
(if (zero? n)
l
(rng (- n 1) (cons n l)))))
If the sublists (1 ... n) can all be the same list (i.e., the actual list object is the same), then you can create it just once:
(define (createlist m n)
(let ((sublist (range n)))
(map (lambda (main)
(list main sublist))
(range m))))
Otherwise, if they need to be distinct, you can generate one for each of 1 ... m:
(define (createlist m n)
(map (lambda (main)
(list main (range n)))
(range m)))
Trying to make a list that has n elements with each of those lists having r elements. i.e.
(function 2 3) would be (list (list 0 0 0)(list 0 1 2)). And those elements are made by multiplying the nth element by the rth element starting at 0. This is my code:
(define (nr nc)
(build-list nr (lambda (x)
(build-list nc (lambda (x) (* x 1))))))
so I have (function 2 3) coming out to (list (list 0 1 2)(list 0 1 2)) and I can't figure out how to multiply the first list by 0, the second by 1, third by 2, and so on.
You were close:
(define (build nr nc)
(build-list nr (lambda (r)
(build-list nc (lambda (c) (* r c))))))
> (build 2 3)
'((0 0 0) (0 1 2))
> (build 3 3)
'((0 0 0) (0 1 2) (0 2 4))
An alternative:
(define (build2 nr nc)
(for/list ([r nr])
(for/list ([c nc])
(* r c))))
(define (range n)
(define (range-iter i accum)
(if (= i 0) (cons 0 accum)
(range-iter (- i 1) (cons i accum))))
(range-iter (- n 1) `()))
(define (nested-list n r)
(map
(lambda (multiplier)
(map
(lambda (cell) (* cell multiplier))
(range r)))
(range n)))