Be careful using recursion on long lists. You could run into stack overflows, especially since AutoLisp does not do tail-call otimization. Other than that good functional code, though firstn & GroupByNum are not tail recursive - so even if ALisp was optimizing it wouldn't work on these.
BTW, "Lazy" has slightly different connotation in some programming circles. Rather than being a way to describe slow running programs, it actually means the opposite: A lazy algorithm only calculates the results as and when needed, such that it uses the least amount of resources and takes only as little time as needed - then builds on its results afterwards without re-calculating for each new query.
Unfortunately a true lazy algorithm isn't possible in AutoLisp. We don't have access to reference calling on variables, not to mention an easy OOP system. But you can do something similar using a cached store of results - though I'm not sure it would be faster in all cases. Especially this one where each call could be on a totally different list and number combination.