How to not recurse twice in LISP
up vote
3
down vote
favorite
I'm trying to write a program that returns the Pell numbers sequence based on a given number.
For example (pellNumb 6)
should return a list (0 1 2 5 12 29 70)
This is my code so far.
I am able of calculating the numbers, but I am not able of skipping the double recursion.
(defun base (n)
(if (= n 0)
0
(if (= n 1)
1)))
(defun pellNumb (n)
(if (or (= n 0) (= n 1))
(base n)
(let ((x (pellNumb (- n 2))))
(setq y (+ (* 2 (pellNumb (- n 1))) x))
(print y))))
The output for (pellNumb 4)
is 2 2 5 12
, and this is because i'm recursing to (pellNumb 2)
twice.
Is there a way to skip that, and store these values in a list ?
Thanks!
lisp common-lisp
add a comment |
up vote
3
down vote
favorite
I'm trying to write a program that returns the Pell numbers sequence based on a given number.
For example (pellNumb 6)
should return a list (0 1 2 5 12 29 70)
This is my code so far.
I am able of calculating the numbers, but I am not able of skipping the double recursion.
(defun base (n)
(if (= n 0)
0
(if (= n 1)
1)))
(defun pellNumb (n)
(if (or (= n 0) (= n 1))
(base n)
(let ((x (pellNumb (- n 2))))
(setq y (+ (* 2 (pellNumb (- n 1))) x))
(print y))))
The output for (pellNumb 4)
is 2 2 5 12
, and this is because i'm recursing to (pellNumb 2)
twice.
Is there a way to skip that, and store these values in a list ?
Thanks!
lisp common-lisp
Yourbase
function is pointless, since it maps0
to0
,1
to1
and returnsnil
for everything else. Your caller only calls it in the0
and1
case, in which the expression(base n)
reduces ton
.
– Kaz
Nov 8 at 23:51
The uselessbase
function could also be cutely written as(case n (0 0) (1 1))
, or(case n ((0 1) n))
.
– Kaz
Nov 8 at 23:51
add a comment |
up vote
3
down vote
favorite
up vote
3
down vote
favorite
I'm trying to write a program that returns the Pell numbers sequence based on a given number.
For example (pellNumb 6)
should return a list (0 1 2 5 12 29 70)
This is my code so far.
I am able of calculating the numbers, but I am not able of skipping the double recursion.
(defun base (n)
(if (= n 0)
0
(if (= n 1)
1)))
(defun pellNumb (n)
(if (or (= n 0) (= n 1))
(base n)
(let ((x (pellNumb (- n 2))))
(setq y (+ (* 2 (pellNumb (- n 1))) x))
(print y))))
The output for (pellNumb 4)
is 2 2 5 12
, and this is because i'm recursing to (pellNumb 2)
twice.
Is there a way to skip that, and store these values in a list ?
Thanks!
lisp common-lisp
I'm trying to write a program that returns the Pell numbers sequence based on a given number.
For example (pellNumb 6)
should return a list (0 1 2 5 12 29 70)
This is my code so far.
I am able of calculating the numbers, but I am not able of skipping the double recursion.
(defun base (n)
(if (= n 0)
0
(if (= n 1)
1)))
(defun pellNumb (n)
(if (or (= n 0) (= n 1))
(base n)
(let ((x (pellNumb (- n 2))))
(setq y (+ (* 2 (pellNumb (- n 1))) x))
(print y))))
The output for (pellNumb 4)
is 2 2 5 12
, and this is because i'm recursing to (pellNumb 2)
twice.
Is there a way to skip that, and store these values in a list ?
Thanks!
lisp common-lisp
lisp common-lisp
edited Nov 10 at 16:25
Sylwester
33.5k22854
33.5k22854
asked Nov 7 at 18:10
user10619884
Yourbase
function is pointless, since it maps0
to0
,1
to1
and returnsnil
for everything else. Your caller only calls it in the0
and1
case, in which the expression(base n)
reduces ton
.
– Kaz
Nov 8 at 23:51
The uselessbase
function could also be cutely written as(case n (0 0) (1 1))
, or(case n ((0 1) n))
.
– Kaz
Nov 8 at 23:51
add a comment |
Yourbase
function is pointless, since it maps0
to0
,1
to1
and returnsnil
for everything else. Your caller only calls it in the0
and1
case, in which the expression(base n)
reduces ton
.
– Kaz
Nov 8 at 23:51
The uselessbase
function could also be cutely written as(case n (0 0) (1 1))
, or(case n ((0 1) n))
.
– Kaz
Nov 8 at 23:51
Your
base
function is pointless, since it maps 0
to 0
, 1
to 1
and returns nil
for everything else. Your caller only calls it in the 0
and 1
case, in which the expression (base n)
reduces to n
.– Kaz
Nov 8 at 23:51
Your
base
function is pointless, since it maps 0
to 0
, 1
to 1
and returns nil
for everything else. Your caller only calls it in the 0
and 1
case, in which the expression (base n)
reduces to n
.– Kaz
Nov 8 at 23:51
The useless
base
function could also be cutely written as (case n (0 0) (1 1))
, or (case n ((0 1) n))
.– Kaz
Nov 8 at 23:51
The useless
base
function could also be cutely written as (case n (0 0) (1 1))
, or (case n ((0 1) n))
.– Kaz
Nov 8 at 23:51
add a comment |
1 Answer
1
active
oldest
votes
up vote
7
down vote
Get the n
th number
Yes, there is a way - use multiple values:
(defun pell-numbers (n)
"Return the n-th Pell number, n-1 number is returned as the 2nd value.
See https://oeis.org/A000129, https://en.wikipedia.org/wiki/Pell_number"
(check-type n (integer 0))
(cond ((= n 0) (values 0 0))
((= n 1) (values 1 0))
(t (multiple-value-bind (prev prev-1) (pell-numbers (1- n))
(values (+ (* 2 prev) prev-1)
prev)))))
(pell-numbers 10)
==> 2378 ; 985
This is a standard trick for recursive sequences which depend on several previous values, such as the Fibonacci.
Performance
Note that your double recursion means that (pell-numbers n)
has exponential(!) performance (computation requires O(2^n)
time), while my single recursion is linear (i.e., O(n)
).
Moreover, Fibonacci numbers have a convenient property which allows a logarithmic recursive implementation, i.e., taking O(log(n))
time.
Get all the numbers up to n
in a list
If you need all numbers up to the n
th, you need a simple loop:
(defun pell-numbers-loop (n)
(loop repeat n
for cur = 1 then (+ (* 2 cur) prev)
and prev = 0 then cur
collect cur))
(pell-numbers-loop 10)
==> (1 2 5 12 29 70 169 408 985 2378)
If you insist on recursion:
(defun pell-numbers-recursive (n)
(labels ((pnr (n)
(cond ((= n 0) (list 0))
((= n 1) (list 1 0))
(t (let ((prev (pnr (1- n))))
(cons (+ (* 2 (first prev)) (second prev))
prev))))))
(nreverse (pnr n))))
(pell-numbers-recursive 10)
==> (0 1 2 5 12 29 70 169 408 985 2378)
Note that the recursion is non-tail, so the loop version is probably more efficient.
One can, of course, produce a tail recursive version:
(defun pell-numbers-tail (n)
(labels ((pnt (i prev)
(if (= i 0)
prev ; done
(pnt (1- i)
(cond ((null prev) (list 0)) ; n=0
((null (cdr prev)) (cons 1 prev)) ; n=1
(t
(cons (+ (* 2 (or (first prev) 1))
(or (second prev) 0))
prev)))))))
(nreverse (pnt (1+ n) ()))))
(pell-numbers-tail 10)
==> (0 1 2 5 12 29 70 169 408 985 2378)
Hey thanks for the answer. Is there a way to put the values in a list ?
– user10619884
Nov 7 at 18:50
Sure:(multiple-value-list (pell-numbers n))
, but why would you want it instead ofmultiple-value-bind
?
– sds
Nov 7 at 18:55
no they mean all of them, not just the last two. --- also, are you sure it's quadratic and not exponential?
– Will Ness
Nov 7 at 18:57
The assignment asked that the results of the recursion would be stored in a list such that(pellNum 6)
should return (0 1 2 5 12 29 70)
– user10619884
Nov 7 at 18:57
@WillNess: you are right - I just could not believe is was that bad ;-)
– sds
Nov 7 at 19:08
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
7
down vote
Get the n
th number
Yes, there is a way - use multiple values:
(defun pell-numbers (n)
"Return the n-th Pell number, n-1 number is returned as the 2nd value.
See https://oeis.org/A000129, https://en.wikipedia.org/wiki/Pell_number"
(check-type n (integer 0))
(cond ((= n 0) (values 0 0))
((= n 1) (values 1 0))
(t (multiple-value-bind (prev prev-1) (pell-numbers (1- n))
(values (+ (* 2 prev) prev-1)
prev)))))
(pell-numbers 10)
==> 2378 ; 985
This is a standard trick for recursive sequences which depend on several previous values, such as the Fibonacci.
Performance
Note that your double recursion means that (pell-numbers n)
has exponential(!) performance (computation requires O(2^n)
time), while my single recursion is linear (i.e., O(n)
).
Moreover, Fibonacci numbers have a convenient property which allows a logarithmic recursive implementation, i.e., taking O(log(n))
time.
Get all the numbers up to n
in a list
If you need all numbers up to the n
th, you need a simple loop:
(defun pell-numbers-loop (n)
(loop repeat n
for cur = 1 then (+ (* 2 cur) prev)
and prev = 0 then cur
collect cur))
(pell-numbers-loop 10)
==> (1 2 5 12 29 70 169 408 985 2378)
If you insist on recursion:
(defun pell-numbers-recursive (n)
(labels ((pnr (n)
(cond ((= n 0) (list 0))
((= n 1) (list 1 0))
(t (let ((prev (pnr (1- n))))
(cons (+ (* 2 (first prev)) (second prev))
prev))))))
(nreverse (pnr n))))
(pell-numbers-recursive 10)
==> (0 1 2 5 12 29 70 169 408 985 2378)
Note that the recursion is non-tail, so the loop version is probably more efficient.
One can, of course, produce a tail recursive version:
(defun pell-numbers-tail (n)
(labels ((pnt (i prev)
(if (= i 0)
prev ; done
(pnt (1- i)
(cond ((null prev) (list 0)) ; n=0
((null (cdr prev)) (cons 1 prev)) ; n=1
(t
(cons (+ (* 2 (or (first prev) 1))
(or (second prev) 0))
prev)))))))
(nreverse (pnt (1+ n) ()))))
(pell-numbers-tail 10)
==> (0 1 2 5 12 29 70 169 408 985 2378)
Hey thanks for the answer. Is there a way to put the values in a list ?
– user10619884
Nov 7 at 18:50
Sure:(multiple-value-list (pell-numbers n))
, but why would you want it instead ofmultiple-value-bind
?
– sds
Nov 7 at 18:55
no they mean all of them, not just the last two. --- also, are you sure it's quadratic and not exponential?
– Will Ness
Nov 7 at 18:57
The assignment asked that the results of the recursion would be stored in a list such that(pellNum 6)
should return (0 1 2 5 12 29 70)
– user10619884
Nov 7 at 18:57
@WillNess: you are right - I just could not believe is was that bad ;-)
– sds
Nov 7 at 19:08
add a comment |
up vote
7
down vote
Get the n
th number
Yes, there is a way - use multiple values:
(defun pell-numbers (n)
"Return the n-th Pell number, n-1 number is returned as the 2nd value.
See https://oeis.org/A000129, https://en.wikipedia.org/wiki/Pell_number"
(check-type n (integer 0))
(cond ((= n 0) (values 0 0))
((= n 1) (values 1 0))
(t (multiple-value-bind (prev prev-1) (pell-numbers (1- n))
(values (+ (* 2 prev) prev-1)
prev)))))
(pell-numbers 10)
==> 2378 ; 985
This is a standard trick for recursive sequences which depend on several previous values, such as the Fibonacci.
Performance
Note that your double recursion means that (pell-numbers n)
has exponential(!) performance (computation requires O(2^n)
time), while my single recursion is linear (i.e., O(n)
).
Moreover, Fibonacci numbers have a convenient property which allows a logarithmic recursive implementation, i.e., taking O(log(n))
time.
Get all the numbers up to n
in a list
If you need all numbers up to the n
th, you need a simple loop:
(defun pell-numbers-loop (n)
(loop repeat n
for cur = 1 then (+ (* 2 cur) prev)
and prev = 0 then cur
collect cur))
(pell-numbers-loop 10)
==> (1 2 5 12 29 70 169 408 985 2378)
If you insist on recursion:
(defun pell-numbers-recursive (n)
(labels ((pnr (n)
(cond ((= n 0) (list 0))
((= n 1) (list 1 0))
(t (let ((prev (pnr (1- n))))
(cons (+ (* 2 (first prev)) (second prev))
prev))))))
(nreverse (pnr n))))
(pell-numbers-recursive 10)
==> (0 1 2 5 12 29 70 169 408 985 2378)
Note that the recursion is non-tail, so the loop version is probably more efficient.
One can, of course, produce a tail recursive version:
(defun pell-numbers-tail (n)
(labels ((pnt (i prev)
(if (= i 0)
prev ; done
(pnt (1- i)
(cond ((null prev) (list 0)) ; n=0
((null (cdr prev)) (cons 1 prev)) ; n=1
(t
(cons (+ (* 2 (or (first prev) 1))
(or (second prev) 0))
prev)))))))
(nreverse (pnt (1+ n) ()))))
(pell-numbers-tail 10)
==> (0 1 2 5 12 29 70 169 408 985 2378)
Hey thanks for the answer. Is there a way to put the values in a list ?
– user10619884
Nov 7 at 18:50
Sure:(multiple-value-list (pell-numbers n))
, but why would you want it instead ofmultiple-value-bind
?
– sds
Nov 7 at 18:55
no they mean all of them, not just the last two. --- also, are you sure it's quadratic and not exponential?
– Will Ness
Nov 7 at 18:57
The assignment asked that the results of the recursion would be stored in a list such that(pellNum 6)
should return (0 1 2 5 12 29 70)
– user10619884
Nov 7 at 18:57
@WillNess: you are right - I just could not believe is was that bad ;-)
– sds
Nov 7 at 19:08
add a comment |
up vote
7
down vote
up vote
7
down vote
Get the n
th number
Yes, there is a way - use multiple values:
(defun pell-numbers (n)
"Return the n-th Pell number, n-1 number is returned as the 2nd value.
See https://oeis.org/A000129, https://en.wikipedia.org/wiki/Pell_number"
(check-type n (integer 0))
(cond ((= n 0) (values 0 0))
((= n 1) (values 1 0))
(t (multiple-value-bind (prev prev-1) (pell-numbers (1- n))
(values (+ (* 2 prev) prev-1)
prev)))))
(pell-numbers 10)
==> 2378 ; 985
This is a standard trick for recursive sequences which depend on several previous values, such as the Fibonacci.
Performance
Note that your double recursion means that (pell-numbers n)
has exponential(!) performance (computation requires O(2^n)
time), while my single recursion is linear (i.e., O(n)
).
Moreover, Fibonacci numbers have a convenient property which allows a logarithmic recursive implementation, i.e., taking O(log(n))
time.
Get all the numbers up to n
in a list
If you need all numbers up to the n
th, you need a simple loop:
(defun pell-numbers-loop (n)
(loop repeat n
for cur = 1 then (+ (* 2 cur) prev)
and prev = 0 then cur
collect cur))
(pell-numbers-loop 10)
==> (1 2 5 12 29 70 169 408 985 2378)
If you insist on recursion:
(defun pell-numbers-recursive (n)
(labels ((pnr (n)
(cond ((= n 0) (list 0))
((= n 1) (list 1 0))
(t (let ((prev (pnr (1- n))))
(cons (+ (* 2 (first prev)) (second prev))
prev))))))
(nreverse (pnr n))))
(pell-numbers-recursive 10)
==> (0 1 2 5 12 29 70 169 408 985 2378)
Note that the recursion is non-tail, so the loop version is probably more efficient.
One can, of course, produce a tail recursive version:
(defun pell-numbers-tail (n)
(labels ((pnt (i prev)
(if (= i 0)
prev ; done
(pnt (1- i)
(cond ((null prev) (list 0)) ; n=0
((null (cdr prev)) (cons 1 prev)) ; n=1
(t
(cons (+ (* 2 (or (first prev) 1))
(or (second prev) 0))
prev)))))))
(nreverse (pnt (1+ n) ()))))
(pell-numbers-tail 10)
==> (0 1 2 5 12 29 70 169 408 985 2378)
Get the n
th number
Yes, there is a way - use multiple values:
(defun pell-numbers (n)
"Return the n-th Pell number, n-1 number is returned as the 2nd value.
See https://oeis.org/A000129, https://en.wikipedia.org/wiki/Pell_number"
(check-type n (integer 0))
(cond ((= n 0) (values 0 0))
((= n 1) (values 1 0))
(t (multiple-value-bind (prev prev-1) (pell-numbers (1- n))
(values (+ (* 2 prev) prev-1)
prev)))))
(pell-numbers 10)
==> 2378 ; 985
This is a standard trick for recursive sequences which depend on several previous values, such as the Fibonacci.
Performance
Note that your double recursion means that (pell-numbers n)
has exponential(!) performance (computation requires O(2^n)
time), while my single recursion is linear (i.e., O(n)
).
Moreover, Fibonacci numbers have a convenient property which allows a logarithmic recursive implementation, i.e., taking O(log(n))
time.
Get all the numbers up to n
in a list
If you need all numbers up to the n
th, you need a simple loop:
(defun pell-numbers-loop (n)
(loop repeat n
for cur = 1 then (+ (* 2 cur) prev)
and prev = 0 then cur
collect cur))
(pell-numbers-loop 10)
==> (1 2 5 12 29 70 169 408 985 2378)
If you insist on recursion:
(defun pell-numbers-recursive (n)
(labels ((pnr (n)
(cond ((= n 0) (list 0))
((= n 1) (list 1 0))
(t (let ((prev (pnr (1- n))))
(cons (+ (* 2 (first prev)) (second prev))
prev))))))
(nreverse (pnr n))))
(pell-numbers-recursive 10)
==> (0 1 2 5 12 29 70 169 408 985 2378)
Note that the recursion is non-tail, so the loop version is probably more efficient.
One can, of course, produce a tail recursive version:
(defun pell-numbers-tail (n)
(labels ((pnt (i prev)
(if (= i 0)
prev ; done
(pnt (1- i)
(cond ((null prev) (list 0)) ; n=0
((null (cdr prev)) (cons 1 prev)) ; n=1
(t
(cons (+ (* 2 (or (first prev) 1))
(or (second prev) 0))
prev)))))))
(nreverse (pnt (1+ n) ()))))
(pell-numbers-tail 10)
==> (0 1 2 5 12 29 70 169 408 985 2378)
edited Nov 9 at 13:09
answered Nov 7 at 18:39
sds
38.3k1492166
38.3k1492166
Hey thanks for the answer. Is there a way to put the values in a list ?
– user10619884
Nov 7 at 18:50
Sure:(multiple-value-list (pell-numbers n))
, but why would you want it instead ofmultiple-value-bind
?
– sds
Nov 7 at 18:55
no they mean all of them, not just the last two. --- also, are you sure it's quadratic and not exponential?
– Will Ness
Nov 7 at 18:57
The assignment asked that the results of the recursion would be stored in a list such that(pellNum 6)
should return (0 1 2 5 12 29 70)
– user10619884
Nov 7 at 18:57
@WillNess: you are right - I just could not believe is was that bad ;-)
– sds
Nov 7 at 19:08
add a comment |
Hey thanks for the answer. Is there a way to put the values in a list ?
– user10619884
Nov 7 at 18:50
Sure:(multiple-value-list (pell-numbers n))
, but why would you want it instead ofmultiple-value-bind
?
– sds
Nov 7 at 18:55
no they mean all of them, not just the last two. --- also, are you sure it's quadratic and not exponential?
– Will Ness
Nov 7 at 18:57
The assignment asked that the results of the recursion would be stored in a list such that(pellNum 6)
should return (0 1 2 5 12 29 70)
– user10619884
Nov 7 at 18:57
@WillNess: you are right - I just could not believe is was that bad ;-)
– sds
Nov 7 at 19:08
Hey thanks for the answer. Is there a way to put the values in a list ?
– user10619884
Nov 7 at 18:50
Hey thanks for the answer. Is there a way to put the values in a list ?
– user10619884
Nov 7 at 18:50
Sure:
(multiple-value-list (pell-numbers n))
, but why would you want it instead of multiple-value-bind
?– sds
Nov 7 at 18:55
Sure:
(multiple-value-list (pell-numbers n))
, but why would you want it instead of multiple-value-bind
?– sds
Nov 7 at 18:55
no they mean all of them, not just the last two. --- also, are you sure it's quadratic and not exponential?
– Will Ness
Nov 7 at 18:57
no they mean all of them, not just the last two. --- also, are you sure it's quadratic and not exponential?
– Will Ness
Nov 7 at 18:57
The assignment asked that the results of the recursion would be stored in a list such that
(pellNum 6)
should return (0 1 2 5 12 29 70)– user10619884
Nov 7 at 18:57
The assignment asked that the results of the recursion would be stored in a list such that
(pellNum 6)
should return (0 1 2 5 12 29 70)– user10619884
Nov 7 at 18:57
@WillNess: you are right - I just could not believe is was that bad ;-)
– sds
Nov 7 at 19:08
@WillNess: you are right - I just could not believe is was that bad ;-)
– sds
Nov 7 at 19:08
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53195333%2fhow-to-not-recurse-twice-in-lisp%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Your
base
function is pointless, since it maps0
to0
,1
to1
and returnsnil
for everything else. Your caller only calls it in the0
and1
case, in which the expression(base n)
reduces ton
.– Kaz
Nov 8 at 23:51
The useless
base
function could also be cutely written as(case n (0 0) (1 1))
, or(case n ((0 1) n))
.– Kaz
Nov 8 at 23:51