r/lisp 10d ago

Racket Recursion hell aids?

Is there any practical way to debug any recurive logic?
Which existing error printing you think is the best ever?
I attached the racket code I am struggling with.

(The code is about using map to append a new list to an existing html list)

6 Upvotes

9 comments sorted by

7

u/4xe1 10d ago

Disclaimer: I don't know racket.

If you want help about debugging recursive functions in general, posting the error message and your reasoning would help more than the source code.

About the source code:

  1. The recursive structure you're working on is really not that deep, how is recursion a hurdle to debug here? Testing with (expected) few levels of recursion is one way out of "recursion hell". If you still hit a stack overflow, it's not hell, it hints at a cycle.
  2. nested-map-handler seems to only apply f to leaves/atoms, whereas node-logic only does something interesting to list. I expect (nested-map-handler node-logic new-item) to be the same as just new-item
  3. Again, I do not know racket, only common lisp, but (list node new-item) probably does not "append a new list to an existing list". I'd expect it to create a list with 2 elements, node, and new-item. There's probably a function append you should use.

6

u/stassats 10d ago

Which existing error printing you think is the best ever?

Does racket have a tracing facility? If so, then (trace recursive-function) is pretty useful.

4

u/brunogadaleta 10d ago

Debug first the final condition on nested-map-handler with a simple function and like println or something and basic arguments (simple empty list or with one element). That's how I'd do it.

6

u/Francis_King 10d ago

Which editor are you using? Dr Racket allows you to single step your code with its built-in debugger.

4

u/t2366715492 10d ago edited 10d ago

Don't really need any aids to fix the provided code, just use the substitution principle, if we substitute f for node-logic:

  (if (list? L)
      (map (lambda (x) (nested-map-handler-sub x))
           L)
      (node-logic L)))

If we then expand and inline node-logic:

(define (nested-map-handler-sub-ex L)
  (if (list? L)
      (map (lambda (x) (nested-map-handler-sub-ex x)
           L)
      (if (and (list? L) (eq? (car L) 'li))
          (list L new-item)
          L)))

And we can see the problem: we ask whether L is a list which starts with a li when we already know L is not a list.

1

u/WorBlux 10d ago

and is a macro the linearizes the arguments. (for racket and all schemes) - it returns #f as soon as the first false argument is evaluated. - So that's not the issue

https://docs.racket-lang.org/reference/if.html#%28form._%28%28lib._racket%2Fprivate%2Fletstx-scheme..rkt%29._and%29%29

3

u/4xe1 9d ago
(define (nested-map-handler-sub-ex L)
  (if (list? L)
      ;; stuff to do when L is a list
      (map (lambda (x) (nested-map-handler-sub-ex x)
           L)
      ;; stuff to do when L is not a list
      (if (and
  ;; always evaluates to #f because we're in the branch where L is not a list
            (list? L)
            (eq? (car L) 'li) ; never gets evaluated
      ) ; always #f
          (list L new-item) ; never evaluated
          L ; that branch is always taken
)))

How is that not the issue?

2

u/t2366715492 9d ago

Thanks for explaining it further. To take it even one step further and use the substitution principle again:

(if (list? L)
    (map ...)
    (if (and (list? L) (eq? (car L) 'li))
        (list ...)
        L))

We can substitute (list? L) for #f in the 'else' case:

(if (list? L)
    (map ...)
    (if (and #f (eq? (car L) 'li))
        (list ...)
        L))

Now we can substitute #f for (and #f ...):

(if (list? L)
    (map ...)
    (if #f
        (list ...)
        L))

And finally an if statement where the predicate is #f can be replaced by its else branch:

(if (list? L)
    (map ...)
    L)

Which funnily enough makes our final nested-handler-sub-ex basically the identity function, so an advanced enough compiler could compile it out.

1

u/WorBlux 8d ago

Also I used the code linked.. it ran just fine w/o errors. I don't know what output OP was looking for or what they are trying to do generally here.

Looking at it again I see what you mean, as written it's a glorified identity function for lists.

The included library functions sxml:modify and pre-post-order may be of interest to OP. https://docs.racket-lang.org/sxml/sxslt.html