简体   繁体   中英

Return List using recursion with Racket

I am trying to return a list (BST, a binary search tree) from a method that has double recursion. I am trying to implement it as follow:

(define (mapBST BST someFunct)
  (cond
    [(null? BST)
     '()]
       [else (cons (car BST) (someFunct (car (cdr BST)))) (mapBST (car (cdr (cdr BST))) someFunct) (mapBST (car (cdr (cdr (cdr BST)))) someFunct) ]

  )
)

This gets called with this little snippet of code

(define bst 
             '( 3 "3"
                  ( 1 "1"
                     ()
                     ( 2 "2" () ())
                  )
                  ( 5 "5" () () )
            )
) 
(mapBST bst string->number)

I also tried this snippet but it returned ((() ()) ()) :

[else (printf (car (cdr BST))) (cons (mapBST (car (cdr (cdr BST))) someFunct) (mapBST (car (cdr (cdr (cdr BST)))) someFunct)) ]

The result should return the same BST but with number instead of string as the value.

Within your else-expression, you are not properly reconstructing the binary search tree, which is why you are getting an empty list. Changing your else case to

...
[else
 (cons (car BST)
       (cons (someFunct (car (cdr BST)))
             (cons (mapBST (car (cdr (cdr BST))) someFunct)
                   (cons (mapBST (car (cdr (cdr (cdr BST)))) someFunct) empty))))]
...

or

...
[else
 (list (car BST)
       (someFunct (car (cdr BST)))
       (mapBST (car (cdr (cdr BST))) someFunct)
       (mapBST (car (cdr (cdr (cdr BST)))) someFunct))]
...

will fix your problem (both options produce the same list, since (cons 1 (cons 2 empty)) is equivalent to (list 1 2) ).

Here is a full update of mapBST :

(define (mapBST proc BST)
  (cond
    [(null? BST) empty]
    [else
     (list (car BST)
           (proc (cadr BST))
           (mapBST proc (caddr BST))
           (mapBST proc (cadddr BST)))]))

For example,

(define BST '(3 "3" (1 "1" () (2 "2" () ())) (5 "5" () ())))
(mapBST string->number BST)
=> '(3 3 (1 1 () (2 2 () ())) (5 5 () ()))

As pointed out in another answer, you are not actually returning what you think you are in the else clause. Fixing that will make your program work. However this kind of (car (cdr (cdr ...))) thing is how people used to write Lisp in the 1960s, and it rightly got Lisp a bad name because it is utterly opaque. Using things like caddr is better, but only slightly (and how many of them does the language provide? I can never remember). Still better, if your data is conceptually a list, is to use functions with names like first & second because they say what you actually mean (if your data is conceptually a tree of conses, then car &c are better probably). But they still have the 'how many of them are there this week' problem.

The right solution is to use destructuring &/or pattern matching to bind variables according to the shape of your data. This makes your code actually clear. Racket has a comprehensive mechanism for this, which I don't really understand in detail, but I know enough to get me through. Here is (a fixed) version of your function which uses match to do the work:

(define (map-bst bst fn)
  (match bst
    ['() '()]
    [(list 1st 2nd 3rd 4th)
     (list 1st
           (fn 2nd)
           (map-bst 3rd fn)
           (map-bst 4th fn))]
    [_ (error "botch")]))

(note this could do with better variable names: I don't know what the various bits of the structure mean).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM