How can I execute step-by-step debugging in Common Lisp ECL? - common-lisp

I am studying Common Lisp using ECL. I tried referring to https://malisper.me/debugging-lisp-part-1-recompilation/ for the debugging method, but the step execution did not work properly.
When I insert "(break)" and select "RETRY", processing stops first at the break. This is the intended behavior as shown on the page above.
(defun fib (n)
(break)
(if (<= 0 n 1)
(/ 1 0)
(+ (fib (- n 1))
(fib (- n 2)))))
Break
[Condition of type SIMPLE-CONDITION]
The next time I pressed the S key, the following error message was displayed, even though it should have been stepped.
SWANK/BACKEND: ACTIVATE-STEPPING not implemented
[Condition of type SIMPLE-ERROR]
Restarts:
0: [ABORT] Return to sldb level 1.
1: [CONTINUE] Return from BREAK.
2: [RETRY] ​​Retry SLIME REPL evaluation request.
3: [* ABORT] Return to SLIME's top level.
4: [ABORT] ABORT
This may be a problem in the implementation of ECL, but I would like to know what kind of debugging is usually done in ECL.
Best regards,
NOEU

One option: STEP in ECL. Use :h to see commands in the stepper.
> (defun fib (n)
(if (<= 0 n 1)
(/ 1 0)
(+ (fib (- n 1))
(fib (- n 2)))))
FIB
> (step (fib 3))
(FIB 3) -
(BLOCK FIB ...) -
(IF (<= 0 ...) ...) -
(<= 0 ...) -
(+ (FIB #) ...) -
(FIB (- N ...)) -
(- N ...) -
(BLOCK FIB ...) -
(IF (<= 0 ...) ...) -
(<= 0 ...) -
(+ (FIB #) ...) -
(FIB (- N ...)) -
(- N ...) -
(BLOCK FIB ...) -
(IF (<= 0 ...) ...) -
(<= 0 ...) -
(/ 1 ...) -
Condition of type: DIVISION-BY-ZERO
#<a DIVISION-BY-ZERO>
Available restarts:
1. (RESTART-TOPLEVEL) Go back to Top-Level REPL.
Broken at FIB. In: #<process TOP-LEVEL 0x104f16f80>.

Related

recursive code in clojure and class cast exception

(defn fib [n]
(if ((= n 0) 0)
((= n 1) 1)
(:else (+ (fib (- n 1))
(fib (- n 2))))))
(fib 10)
ClassCastException java.lang.Boolean cannot be cast to clojure.lang.IFn
The same exception with the following.
(defn A [x y]
(cond ((= y 0) 0)
((= x 0) (* 2 y))
((= y 1) 2)
(:else (A (- x 1) (A x (- y 1))))))
(A 1 10)
Whats wrong with this unable to understand, please explain ?
You were so close!
(defn A [x y]
(cond (= y 0) 0
(= x 0) (* 2 y)
(= y 1) 2
:else (A (- x 1)
(A x (- y 1)))))
You simply had too many parentheses wrapping the cond forms.
Works fine now:
user=> (A 1 10)
1024
There are some similar issues in your recursive fib function. Pay careful attention to indentation - this will always help you see where your issue lies.
In this particular case the exception ClassCastException java.lang.Boolean cannot be cast to clojure.lang.IFnis being thrown by this line:
((= n 1) 1)
... because (= n 1) is being evaluated to either Boolean true or false, and because this resulting boolean is in the first position of the ((= n 1) 1) form, it means that Clojure will attempt to call the boolean as a function (clojure.lang.IFn).
This is what Clojure is really seeing:
(true 1)
Which is why Clojure is trying to cast a Boolean as an IFn. IFn is a Java interface which represents a callable function.
I hope that makes sense.

Clojure java.lang.Long cannot be cast to clojure.lang.IFn error

I trying to write simple factorial function in clojure, but i am getting this error:
java.lang.Long cannot be cast to clojure.lang.IFn
I know this error is usually due to an extra parenthesis, but I am not sure about this case.
First I wrote function in LISP, and it works as it should.
Code:
(defun factorial (n)
(if (= n 1)
1
(* (factorial (1- n)) n )
)
)
(factorial 5)
Then I tried it in clojure, where it doesn't work.
Clojure code:
(defn factorial [n]
(if (= n 1)
1
(* (factorial(n)) n)
)
)
(defn -main
[& args]
(println(factorial 5))
)
You've got an extra set of parens in your recursive call to factorial, probably because you meant to decrement n, it should be
(defn factorial [n]
(if (= n 1)
1
(* (factorial (dec n)) n) ;; <==
)
)
As MarkNFI showed decrementing has its own operator inc.
But to show you the problem in your code:
(defun factorial (n)
(if (= n 1)
1
(* (factorial (1- n)) n ) ;; (1- n) must be changed to (dec n) or (- n 1)
)
)
(factorial 5)
(1- n) is not the way operators in clojure work. You have to place the operator first. So in your case it would be: (- n 1)

Common Lisp: Why does my tail-recursive function cause a stack overflow?

I have a problem in understanding the performance of a Common Lisp function (I am still a novice). I have two versions of this function, which simply computes the sum of all integers up to a given n.
Non-tail-recursive version:
(defun addup3 (n)
(if (= n 0)
0
(+ n (addup (- n 1)))))
Tail-recursive version:
(defun addup2 (n)
(labels ((f (acc k)
(if (= k 0)
acc
(f (+ acc k) (- k 1)))))
(f 0 n)))
I am trying to run these functions in CLISP with input n = 1000000. Here is the result
[2]> (addup3 1000000)
500000500000
[3]> (addup2 1000000)
*** - Program stack overflow. RESET
I can run both successfully in SBCL, but the non-tail-recursive one is faster (only by a little, but that seems strange to me). I've scoured Stackoverflow questions for answers but couldn't find something similar. Why do I get a stack overflow although the tail-recursive function is designed NOT to put all recursive function calls on the stack? Do I have to tell the interpreter/compiler to optimise tail calls? (I read something like (proclaim '(optimize (debug 1)) to set the debug level and optimize at the cost of tracing abilities, but I don't know what this does).
Maybe the answer is obvious and the code is bullshit, but I just can't figure it out.
Help is appreciated.
Edit: danlei pointed out the typo, it should be a call to addup3 in the first function, so it is recursive. If corrected, both versions overflow, but not his one
(defun addup (n)
"Adds up the first N integers"
(do ((i 0 (+ i 1))
(sum 0 (+ sum i)))
((> i n) sum)))
While it may be a more typical way to do it, I find it strange that tail recursion is not always optimised, considering my instructors like to tell me it's so much more efficient and stuff.
There is no requirement for a Common Lisp implementation to have tail call optimization. Most do, however (I think that ABCL does not, due to limitations of the Java virtual machine).
The documentation of the implementation should tell you what optimization settings should be chosen to have TCO (if available).
It is more idiomatic for Common Lisp code to use one of the looping constructs:
(loop :for i :upto n
:sum i)
(let ((sum 0))
(dotimes (i n)
(incf sum (1+ i))))
(do ((i 0 (1+ i))
(sum 0 (+ sum i)))
((> i n) sum))
In this case, of course, it is better to use the "little Gauß":
(/ (* n (1+ n)) 2)
Well, your addup3 just isn't recursive at all.
(defun addup3 (n)
(if (= n 0)
0
(+ n (addup (- n 1))))) ; <--
It calls whatever addup is. Trying a corrected version in SBCL:
CL-USER> (defun addup3 (n)
(if (= n 0)
0
(+ n (addup3 (- n 1)))))
ADDUP3
CL-USER> (addup3 100000)
Control stack guard page temporarily disabled: proceed with caution
; ..
; Evaluation aborted on #<SB-SYS:MEMORY-FAULT-ERROR {C2F19B1}>.
As you'd expect.
Using GNU CommonLisp, GCL 2.6.12, compilation of addup2 will optimize tail calls, here is what I got:
>(compile 'addup2)
Compiling /tmp/gazonk_3012_0.lsp.
End of Pass 1.
;; Note: Tail-recursive call of F was replaced by iteration.
End of Pass 2.
OPTIMIZE levels: Safety=0 (No runtime error checking), Space=0, Speed=3
Finished compiling /tmp/gazonk_3012_0.lsp.
Loading /tmp/gazonk_3012_0.o
start address -T 0x9556e8 Finished loading /tmp/gazonk_3012_0.o
#<compiled-function ADDUP2>
NIL
NIL
>>(addup2 1000000)
500000500000
>(addup3 1000000)
Error: ERROR "Invocation history stack overflow."
Fast links are on: do (si::use-fast-links nil) for debugging
Signalled by IF.
ERROR "Invocation history stack overflow."
Broken at +. Type :H for Help.
1 Return to top level.
>>(compile 'addup3)
Compiling /tmp/gazonk_3012_0.lsp.
End of Pass 1.
End of Pass 2.
OPTIMIZE levels: Safety=0 (No runtime error checking), Space=0, Speed=3
Finished compiling /tmp/gazonk_3012_0.lsp.
Loading /tmp/gazonk_3012_0.o
start address -T 0x955a00 Finished loading /tmp/gazonk_3012_0.o
#<compiled-function ADDUP3>
NIL
NIL
>>(addup3 1000000)
Error: ERROR "Value stack overflow."
Hope it helps.
In SBCL User Manual:
The compiler is “properly tail recursive.” [...] The elimination of tail-recursive frames can be prevented by disabling tail-recursion optimization, which happens when the debug optimization quality is greater than 2.
And works as is in the REPL of a fresh image:
(defun sum-no-tail (n)
(if (zerop n)
0
(+ n (sum-no-tail (- n 1)))))
(defun sum-tail (n &key (acc 0))
(if (zerop n)
acc
(sum-tail (- n 1) :acc (+ n acc))))
CL-USER> (sum-no-tail 10000)
50005000 (26 bits, #x2FB0408)
CL-USER> (sum-no-tail 100000)
Control stack guard page temporarily disabled: proceed with caution
; Debugger entered on #<SB-KERNEL::CONTROL-STACK-EXHAUSTED {10026620A3}>
[1] CL-USER>
; Evaluation aborted on #<SB-KERNEL::CONTROL-STACK-EXHAUSTED {10026620A3}>
CL-USER> (sum-tail 100000)
5000050000 (33 bits, #x12A06B550)
CL-USER> (sum-tail 1000000)
500000500000 (39 bits, #x746A5A2920)
CL-USER> (sum-tail 10000000)
50000005000000 (46 bits, #x2D7988896B40)
Hope it helps in SBCL.

Recursing in a lambda function

I have the following 2 functions that I wish to combine into one:
(defun fib (n)
(if (= n 0) 0 (fib-r n 0 1)))
(defun fib-r (n a b)
(if (= n 1) b (fib-r (- n 1) b (+ a b))))
I would like to have just one function, so I tried something like this:
(defun fib (n)
(let ((f0 (lambda (n) (if (= n 0) 0 (funcall f1 n 0 1))))
(f1 (lambda (a b n) (if (= n 1) b (funcall f1 (- n 1) b (+ a b))))))
(funcall f0 n)))
however this is not working. The exact error is *** - IF: variable F1 has no value
I'm a beginner as far as LISP goes, so I'd appreciate a clear answer to the following question: how do you write a recursive lambda function in lisp?
Thanks.
LET conceptually binds the variables at the same time, using the same enclosing environment to evaluate the expressions. Use LABELS instead, that also binds the symbols f0 and f1 in the function namespace:
(defun fib (n)
(labels ((f0 (n) (if (= n 0) 0 (f1 n 0 1)))
(f1 (a b n) (if (= n 1) b (f1 (- n 1) b (+ a b)))))
(f0 n)))
You can use Graham's alambda as an alternative to labels:
(defun fib (n)
(funcall (alambda (n a b)
(cond ((= n 0) 0)
((= n 1) b)
(t (self (- n 1) b (+ a b)))))
n 0 1))
Or... you could look at the problem a bit differently: Use Norvig's defun-memo macro (automatic memoization), and a non-tail-recursive version of fib, to define a fib function that doesn't even need a helper function, more directly expresses the mathematical description of the fib sequence, and (I think) is at least as efficient as the tail recursive version, and after multiple calls, becomes even more efficient than the tail-recursive version.
(defun-memo fib (n)
(cond ((= n 0) 0)
((= n 1) 1)
(t (+ (fib (- n 1))
(fib (- n 2))))))
You can try something like this as well
(defun fib-r (n &optional (a 0) (b 1) )
(cond
((= n 0) 0)
((= n 1) b)
(T (fib-r (- n 1) b (+ a b)))))
Pros: You don't have to build a wrapper function. Cond constructt takes care of if-then-elseif scenarios. You call this on REPL as (fib-r 10) => 55
Cons: If user supplies values to a and b, and if these values are not 0 and 1, you wont get correct answer

Trying to understand "let" in scheme

I'm trying to expand a simple fibonacci function, and I need to use the values for each term more than once. So, I figured I'd use let to hold onto the values. But, I'm not getting what I think I should out of the function.
Here is the original fib function:
(define (fib n)
(if (< n 2)
n
(+ (fib (- n 1)) (fib (- n 2)))))
Here is my attempt at doing the same thing, but with let:
(define (fib-with-let n)
(if (< n 2)
0
(let ((f1 (fib-with-let (- n 1)))
(f2 (fib-with-let (- n 2))))
(+ f1 f2))))
Results:
> (fib 10)
55
> (fib-with-let 10)
0
Thanks!
You made a typo:
(if (< n 2)
0
...)
You mean n.
You mistyped your base case. In the first version you had:
(if (< n 2)
n
But then in your latter version you wrote:
(if (< n 2)
0
So just change 0 to n.
Your let is not really doing anything. You are still doing all of the extra calculations. Just because you define f1 as (fib-with-let (- n 1)) doesn't mean you won't compute the fib of n-1 again. f2 does not use f1. If you wanted f2 to see f1 you would use let*. However, even this is not really what you want.
As evidence of this, here are the running times for fib(35) and fib-with-let(35):
(time (fib 35))
cpu time: 6824 real time: 6880 gc time: 0
(time (fib-with-let 35))
cpu time: 6779 real time: 6862 gc time: 0
What you really want to do to avoid extra computations is use dynamic programming and recurse in a bottom-up fashion.
What you want is the following code:
(define (dynprog-fib n)
(if (< n 2)
n
(dynprog-fib-helper 1 1 2 n)))
(define (dynprog-fib-helper n1 n2 current target)
(if (= current target)
n2
(dynprog-fib-helper n2 (+ n1 n2) (add1 current) target)))
(time (dynprog-fib 35))
cpu time: 0 real time: 0 gc time: 0
(time (dynprog-fib 150000))
cpu time: 2336 real time: 2471 gc time: 644
As you can see, you can do the first 150,000 fibs in a third of the time the naive approach takes.
Since it looks like you are confused about what let does let me illustrate better:
When you say:
(let ((a 1)
(b 2))
(+ a b))
What you are saying is, let a be 1, and b be 2, add them together.
If you instead said:
(let ((a 1)
(b (+ a 1))
(+ a b))
Can you guess what you'd get? Not 3. It would be blow up with expand: unbound identifier in module in: a
In simple let, your assignments cannot see each other.
If you wanted to write the above you would have to use let*:
(let* ((a 1)
(b (+ a 1))
(+ a b))
That would give you the 3 you expect. let* essentially expands to:
(let ((a 1))
(let ((b (+ a 1)))
(+ a b)))
What you thought you were doing with the lets is called memoization. It's a technique where you store intermediate values so you don't have to repeat them. Let, however, does not do that for you.
Although your problem is a typo in your fib-with-let function, in its simplest form, let is "syntatic-sugar" for an anonymous lambda followed by the arguments that are then evaluated and passed to the lamba, which is then evaluated and a final value returned. So
(let ((f1 (fib-with-let (- n 1)))
(f2 (fib-with-let (- n 2))))
(+ f1 f2))
would be re-written without let to look like
((lambda (f1 f2) (+ f1 f2))(fib-with-let (- n 1))(fib-with-let (- n 2)))

Resources