I need to implement a procedure called inverse-tree that receives a tree
whose nodes data values are numbers and booleans and returns the equivalent
tree whose nodes satisfy the following:
- If the equivalent node of the original tree is a number, then the resulting tree’s node is −1· that node value
- If the equivalent node of the original tree is a boolean, then the resulting tree’s node is the logical not of that node value
Examples:
> (inverse-tree ’())
’()
> (inverse-tree ’(5))
’(-5)
> (inverse-tree ’(0))
’(0)
> (inverse-tree ’(#f))
’(#t)
> (inverse-tree ’(#t))
’(#f)
> (inverse-tree ’(-5 (1 (-2) (3) (#f)) (#t)))
’(5 (-1 (2) (-3) (#t)) (#f))
The representation of a (possibly empty or non-complete) tree in Scheme is as follows: the first element in every nesting level represents the root of the sub-tree. The rest of the elements are the children (each of them is a tree, of course). A leaf is represented by a list with only one element (the leaf value). A completely empty tree is represented by the empty list.
more info at Scheme altering tree values.
Write down what the possible inputs are (there are three cases in the description of what a tree looks like) and define the result for each case.
Here is the general tree-traversal you need to implement:
- If the tree is empty:
- If the tree is a leaf:
- Otherwise:
- Invert the node's value
- Produce a new tree by combining this inverted value with the results of inverting each subtree
You're probably going to want to read about map
in your favourite Scheme book.
It's possible (but I suspect that it's a later exercise) to generalise this so it applies an arbitrary function in the tree, just like map
does with lists.
The explanation for the tree structure doesn't seem to work. (1 (-2) (3)
is a node, but 1
is not a parent. However it seems you can look at the whole thing as a binary tree where pairs are nodes and the empty list is an empty tree and any other value is a leaf node.
The abstraction would look like this:
(define make-tree cons)
(define tree-left car)
(define tree-right cdr)
(define tree? pair?)
(define empty-tree '())
You can map over the values of a tree like this:
(define (map-tree proc tree)
(cond ((eq? empty-tree tree) empty-tree)
((tree? tree)
(make-tree (map-tree proc (tree-left tree))
(map-tree proc (tree-right tree))))
(else (proc tree))))
Example:
(map-tree (lambda (v) (+ v 1)) '(1 (2) 3))
; ==> (2 (3) 4)
Obviously you need to replace the first argument with a procedure that works like this:
(inverse #f) ; ==> #t
(inverse #t) ; ==> #f
(inverse 5) ; ==> -5
;; optional
(inverse 'xxx) ; ==> xxx
Then it's easy to make your procedure:
(define (inverse-tree tree)
(map-tree inverse tree))
(inverse-tree ’(-5 (1 (-2) (3) (#f)) (#t)))
; ==> (5 (-1 (2) (-3) (#t)) (#f))
Now if you cannot use abstractions you would need to use the substitution rules. eg.
(define (tree-inc v)
(map-tree (lambda (v) (+ v 1)) v))
; ==
(define (tree-inc tree)
(cond ((eq? '() tree) '())
...
(else (+ (car tree) 1))))
There you have it. More difficult to read and reason about than one that uses abstractions. Good luck with that.
After a lot of digging and understanding the syntax better I cam up with a simple 1 function solution:
(define (inverse-tree tree)
(cond ((eq? '() tree) '())
((pair? tree)
(cons (inverse-tree (car tree))
(inverse-tree (cdr tree))))
(else ((lambda(x) (if (boolean? x) (not x) (- x))) tree))))
I think that should work:
(define inverse-tree
(lambda (tree)
(if (null? tree)
'()
(if (number? (car tree))
(cons (* -1 (car tree)) (inverse-tree (cdr tree)))
(if (boolean? (car tree))
(cons (not (car tree)) (inverse-tree (cdr tree)))
(cons (inverse-tree (car tree)) (inverse-tree (cdr tree))))))))