.. raw:: html
.. _FP3:
.. raw:: html
.. |--| unicode:: U+2013 .. en dash
.. |---| unicode:: U+2014 .. em dash, trimming surrounding whitespace
:trim:
.. odsalink:: AV/PL/FP/FP3CON.css
.. This file is part of the OpenDSA eTextbook project. See
.. http://opendsa.org for more details.
.. Copyright (c) 2012-2020 by the OpenDSA Project Contributors, and
.. distributed under an MIT open source license.
.. avmetadata::
:author: David Furcy and Tom Naps
===================================
Recurring On Lists That Aren't Flat
===================================
Deep Recursion in FP
--------------------
In the previous section, we limited our treatment of list-processing
functions to operating on *flat* lists of integers, that is, lists that
do not themselves contain nested inner lists. In this section, we
will consider how to operate on lists that can contain not only
integers, but also lists. This will lead to a discussion of *deep recursion*,
which can handle trees represented as lists of lists of ... lists of integers
nested arbitrarily deep.
A good guideline for deep recursion is the following. When recurring
on a list *lst* of elements that may themselves be lists, recur on both
*fp.hd(lst)* and *fp.tl(lst)*, after making sure that *lst* is not empty and
that *fp.hd(lst)* is indeed a list.
Consider the following **tree_test** list as an example::
var tree_test = [ 14,
[ 7, [], [12, [], []] ],
[ 26,
[ 20, [17, [], []], [] ],
[ 31, [], [] ]
]
]
We want to develop a function that takes in an integer tree
represented as a list of lists of ... lists of integers and returns the sum
of the integers in the tree.
..
.. ::
..
.. var sumTree = function (ns) {
.. if (fp.isNull(ns)) {
.. return 0;
.. } else if (???????) {
.. return ?????????;
.. } else {
.. return ?????????;
.. }
.. }
..
.. inlineav:: FP3Code1CON ss
:points: 0.0
:required: False
:threshold: 1.0
:long_name: Illustrate Deep Recursion On List To Return Numeric Value
:output: show
Now that we have seen a deep recursion example in the preceding
slide show, consider the slight modification in the following review
problem.
.. avembed:: Exercises/PL/DeepRecur1.html ka
:module: FP3
:points: 1.0
:required: True
:threshold: 1
:exer_opts: JXOP-debug=true&JOP-lang=en&JXOP-code=pseudo
:long_name: Deep Recursion 1
Deep Recursion on Binary Search Trees
-------------------------------------
Note that, although our **sumTree** function would work on an arbitrary
nested list, our particular **tree\_test** example is actually a
binary search tree under the interpretation that the first nested list
following a given number is the left subtree of that number, which
contains only values less than or equal to the number, and the second
nested list following a number is the right subtree, which contains
only numbers greater than the given number. Using this representation of
a tree, we could develop the helper functions below that
process those nested lists that are binary search trees.
::
// Return the left subtree
var left = function (bst) {
return fp.hd(fp.tl(bst));
};
// Return the right subtree
var right = function (bst) {
return fp.hd(fp.tl(fp.tl(bst)));
};
// Is this tree a leaf node?
var isLeaf = function (tree) {
return fp.isNull(left(tree)) && fp.isNull(right(tree));
};
Using these helper functions, we can easily write a function **path**
(with one caveat addressed below)
**var path = function (n, bst) { ... };**
where **n** is a number and **bst** is a binary search tree that
**contains the number n**. **path** should return a list of 0’s and
1’s showing how to find the node containing **n**, where 1 indicates
"go right" and 0 indicates "go left". If **n** is found at the root, the
empty list is returned. Example usage::
> var tree_test = [ 14,
[ 7, [], [12, [], []] ],
[ 26,
[ 20, [17, [], []], [] ],
[ 31, [], [] ]
]
]
> path(17, tree_test)
[1, 0, 0]
The caveat in the function we develop is that it is not prepared to
return some type of error signal when **n** is not contained in the
tree. We will address this shortcoming in the
`section on continuation passing style `_.
.. inlineav:: FP3Code2CON ss
:points: 0.0
:required: False
:threshold: 1.0
:long_name: Illustrate Deep Recursion On BST
:output: show
Now that we've seen how to use **cons** in conjunction with lists
being returned from deep recursion, consider the following review
problem. It also deals with deep recursion and more specifically with
the **subst** function that was described in :ref:`subst`.
.. avembed:: Exercises/PL/DeepRecur2.html ka
:module: FP3
:points: 1.0
:required: True
:threshold: 1
:exer_opts: JXOP-debug=true&JOP-lang=en&JXOP-code=pseudo
:long_name: Deep Recursion 2
Practice with Deep Recursion
----------------------------
This problem is similar to (and assumes that you have solved) the
previous problem.
.. avembed:: Exercises/PL/DeepRecur3.html ka
:module: FP3
:points: 1.0
:required: True
:threshold: 1
:exer_opts: JXOP-debug=true&JOP-lang=en&JXOP-code=pseudo
:long_name: Deep Recursion 3
More Practice with Deep Recursion
---------------------------------
As a final example and to give you a lot more practice with deep
recursion, consider the following randomized exercise. You have to
solve it correctly three times in a row.
.. avembed:: Exercises/PL/DeepRecur4.html ka
:module: FP3
:points: 1.0
:required: True
:threshold: 3
:exer_opts: JXOP-debug=true&JOP-lang=en&JXOP-code=pseudo
:long_name: Deep Recursion 4
.. odsascript:: AV/PL/FP/FP3Code1CON.js
.. odsascript:: AV/PL/FP/FP3Code2CON.js