Forum Discussion
Lambda Example: Generate Fibonacci series
SergeiBaklan Good point. I think FIB should probably truncate decimals to integers if entered as parameters to be consistent with other functions. It seems not much change is required to do that because SEQUENCE and INDEX functions already do this (though to be precise one should check values very close to integer as you say.)
=LAMBDA(n,
IF(n<3,
SEQUENCE(n,,0),
LET(b,FIB(n-1),
IF(SEQUENCE(n)<INT(n),b,INDEX(b,n-1)+INDEX(b,n-2)))
))
Viz I found this pretty challenging and don't find recursion very intuitive either. I first laid out the expected results for all input values from 1 to 10 horizontally referring to prior results using spill operator and then substituted LET to make it more efficient.
- tbouldenJan 18, 2021Iron Contributor
lori_mWas struggling to figure out how to extend an array as well, thanks for this example. Using your FIB array extension as a hint I've got a generic iterator layout after struggling with the formula a bit. Formula was returning a #NUM error, and figured out that TYPE(INDEX(Seed,ROWS(Seed)))=64 (array) rather than 1 for number. Any ideas on better way to do this? Decided to work through Project Euler problems to wrap my head around LAMBDA usage and this is part of my solution to question on Collatz sequence.
=LET(n,<cell_ref or hardcode number>,
LET(Next,LAMBDA(Prior,IF(ISEVEN(Prior),Prior/2,Prior*3+1)),
Seed,SEQUENCE(1,1,n,0),
Iterate,LAMBDA(ME,Seed,
LET(PriorVal,NUMBERVALUE(ARRAYTOTEXT(INDEX(Seed,ROWS(Seed)))),
CurrVal,Next(PriorVal),
CurrResult,IF(SEQUENCE(ROWS(Seed)+1)<(ROWS(Seed)+1),Seed,CurrVal),
IF(PriorVal=1,Seed,IF(CurrVal=1,CurrResult,ME(ME,CurrResult)))
)
),
Iterate(Iterate,Seed)
)
)- PeterBartholomew1Jan 18, 2021Silver Contributor
I have still to get to grips with your formula; I find recursive formulae especially opaque!
One observation, though. It is possible to conduct the recursion, and maintain a counter that could be used as a backup termination criterion, without building the array as you go.
When the end point is reached, all the values obtained along the way are still present within the memory stack and are accessible one at a time following return from the previous level. In the Fibonacci example I used this to combine the current value and the return array to build the complete series as an array of known length.
- tbouldenJan 19, 2021Iron ContributorThanks Peter, I reviewed your version, and translated it for my case; I'll have to experiment with it some, but for this particular problem, I run up against the stack depth (about 170ish recursions deep with the parameter count/setup I'm using). I'm pleased that with your version, I avoid the NUMBERVALUE(ARRAYTOTEXT(INDEX(...))) usage, though I imagine there is probably a better way to handle that as well. Thanks again!
PS: Part of wrapping my head around this is has been this useful post: https://www.sumproduct.com/news/article/lambda-formulaic-recursion-its-all-about-me
- SergeiBaklanJan 07, 2021Diamond Contributor
In case of FIB() - yes, maybe, but the question is more general. How to find the compromise with error handling within lambdas which definitely could reduce the performance. Keep #VALUE! and #N/A as in native functions or add error handling and when. Decision is on case by case basis, I don't see common rule.
Another side effect is rounding which could give an error only on some inner iteration if use recursion, probably it will be bit hard to debug in some cases.
- VizJan 07, 2021Brass Contributor
There may be a better solution but one approach I can think about handling error would be to have Lambda in two layers.
I am just putting the pseudo code here,
MAIN
=Lambda(n, IF(n<>int(n),"Enter integer",FIB(n)))
FIB
=Lambda(n, ..................)
I am new to recursive programming. So, I am not sure if this is the only solution. Perhaps better option exists.
- SergeiBaklanJan 07, 2021Diamond Contributor
The problem is that =n=INT(n) could return TRUE for the first iteration and FALSE on next ones if the difference is around 14th digit.