{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "### CS 200: Deep Recursion\n", "\n", "\n", "
\n",
    "\n",
    "In regular recursion, we would recurse over the top level elements of a list, string, or tuple.\n",
    "\n",
    "There are other recursive data structures that have multiple levels, for example, trees.\n",
    "\n",
    "A tree, like the UNIX file system, has a root node.  Each node can contain terminals nodes, called \"leaves\", or other nodes or branches.  These nodes are called children.  The main node is the parent.  For example, in a UNIX directory, .. refers to the parent directory and . refers to the child directory.  If a UNIX program spawns a process, the new process is the child and the originating process is the parent.  (In C, you use the fork command to create a child process.)\n",
    "\n",
    "The recursive function must process each node and all the children nodes.\n",
    "\n",
    "Our first example procedure is maptree(proc, tree) which creates a copy of the given tree, with each leaf node replaced by proc(leafnode)\n",
    "\n",
    "The base case is when a node is empty, an integer, or some other leaf node.\n",
    "\n",
    "The recursive case is a list, in which the function is called recursively on each element of the list, and returns a copy of the list with appropriate modifications.\n",
    "\n",
    "The functions in this notebook are from recursion.py\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['1', '2', '3', '4']"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(map(str,[1,2,3,4]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 4, 9, 16]"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(map(lambda x: x*x , [1,2,3,4]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['1', '2', '[3, 4]']"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(map(str, [1,2,[3,4]]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "list"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type([])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def maptree(proc,tree):\n",
    "    if tree == []:\n",
    "        return tree\n",
    "    if not type(tree) == type([]):\n",
    "        return proc(tree)\n",
    "    result = []\n",
    "    for c in tree:\n",
    "        result.append(maptree(proc, c))\n",
    "    return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "l = [1,2,[3,4,[5,6],'a', 'b', []]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, [3, 4, [5, 6], 'a', 'b', []]]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "l"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['1', '2', ['3', '4', ['5', '6'], 'a', 'b', []]]"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "maptree(str, l)  ## convert every leaf into a string"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def square(x):\n",
    "    if type(x) == int:\n",
    "        return x*x\n",
    "    else:\n",
    "        return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 4, [9, 16, [25, 36], 'a', 'b', []]]"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "maptree(square, l)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, [3, 4, [5, 6], 'a', 'b', []]]"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "l"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[(1, 1),\n",
       " (2, 2),\n",
       " [(3, 3), (4, 4), [(5, 5), (6, 6)], ('a', 'a'), ('b', 'b'), []]]"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "maptree(lambda x: (x,x), l)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "int"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 4, [9, 16, [25, 36], 'a', 'b', []]]"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "maptree(lambda x: x*x if type(x) == type(1) else x, l)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will redefine maptree using a list comprehension"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "def lcmaptree(proc,tree):\n",
    "    if tree == []:\n",
    "        return tree\n",
    "    if not type(tree) == type([]):\n",
    "        return proc(tree)\n",
    "    return [lcmaptree(proc,x) for x in tree]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['1', '2', ['3', '4', ['5', '6'], 'a', 'b', []]]"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lcmaptree(str, l)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 4, [9, 16, [25, 36], 'a', 'b', []]]"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lcmaptree(square, l)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[(1, 1),\n",
       " (2, 2),\n",
       " [(3, 3), (4, 4), [(5, 5), (6, 6)], ('a', 'a'), ('b', 'b'), []]]"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lcmaptree(lambda x: (x,x), l)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 4, [9, 16, [25, 36], 'a', 'b', []]]"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lcmaptree(lambda x: x*x if type(x) == type(1) else x, l)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here is a nested list comprehension version of maptree."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "def lclcmaptree(proc,tree):\n",
    "    return [[lclcmaptree(proc,x) for x in t] if type(t) == list\n",
    "            else t if t == [] else proc(t) for t in tree]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "'int' object is not iterable",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m/tmp/ipykernel_653364/3129645351.py\u001b[0m in \u001b[0;36m