|
1 | 1 | { |
2 | 2 | "cells": [ |
3 | 3 | { |
4 | | - "cell_type": "code", |
5 | | - "execution_count": 2, |
6 | | - "id": "930ec69a-d8d3-44af-8de9-967fe18b2a5d", |
| 4 | + "cell_type": "markdown", |
| 5 | + "id": "7993cc74-47c2-4064-a5f2-145bd3248638", |
7 | 6 | "metadata": {}, |
8 | | - "outputs": [], |
9 | 7 | "source": [ |
10 | | - "from typing import Callable, TypeAlias" |
| 8 | + "Although it may seem impossible at first, it is in fact possible to define a recursive function using lambda functions." |
| 9 | + ] |
| 10 | + }, |
| 11 | + { |
| 12 | + "cell_type": "markdown", |
| 13 | + "id": "6191e0ce-e3fe-41d6-8e67-e51315fb13a1", |
| 14 | + "metadata": {}, |
| 15 | + "source": [ |
| 16 | + "The first step is to define a function that takes a parameter that is a callable, and applies it to itself.\n", |
| 17 | + "```\n", |
| 18 | + " lambda f: f(f)\n", |
| 19 | + "```" |
11 | 20 | ] |
12 | 21 | }, |
13 | 22 | { |
14 | 23 | "cell_type": "code", |
15 | | - "execution_count": 4, |
16 | | - "id": "4c399a58-f64b-4e66-9d78-6b2470bb1aaf", |
| 24 | + "execution_count": 1, |
| 25 | + "id": "ecb5c7d3-d2c3-4751-9bc0-a3d6701ba653", |
17 | 26 | "metadata": {}, |
18 | | - "outputs": [], |
| 27 | + "outputs": [ |
| 28 | + { |
| 29 | + "name": "stdout", |
| 30 | + "output_type": "stream", |
| 31 | + "text": [ |
| 32 | + "<built-in function print>\n" |
| 33 | + ] |
| 34 | + } |
| 35 | + ], |
19 | 36 | "source": [ |
20 | | - "IntFunc: TypeAlias = Callable[(int, ), int]" |
| 37 | + "(lambda f: f(f))(print)" |
21 | 38 | ] |
22 | 39 | }, |
23 | 40 | { |
24 | 41 | "cell_type": "markdown", |
25 | | - "id": "7993cc74-47c2-4064-a5f2-145bd3248638", |
| 42 | + "id": "531b2bb7-b9b9-4ec3-8979-bd04097107ab", |
26 | 43 | "metadata": {}, |
27 | 44 | "source": [ |
28 | | - "Although it may seem impossible at first, it is in fact possible to define a recursive function using lambda functions." |
| 45 | + "In the example above, the lambda function is called with the `print` function as a parameter, hence that function will be applied to itself." |
| 46 | + ] |
| 47 | + }, |
| 48 | + { |
| 49 | + "cell_type": "code", |
| 50 | + "execution_count": 2, |
| 51 | + "id": "b0a5e592-6382-4bbd-a262-6b4202961079", |
| 52 | + "metadata": {}, |
| 53 | + "outputs": [ |
| 54 | + { |
| 55 | + "name": "stdout", |
| 56 | + "output_type": "stream", |
| 57 | + "text": [ |
| 58 | + "<built-in function print>\n" |
| 59 | + ] |
| 60 | + } |
| 61 | + ], |
| 62 | + "source": [ |
| 63 | + "print(print)" |
29 | 64 | ] |
30 | 65 | }, |
31 | 66 | { |
32 | 67 | "cell_type": "markdown", |
33 | 68 | "id": "b09f4ae1-4ea3-4257-abf7-1b830ab8593c", |
34 | 69 | "metadata": {}, |
35 | 70 | "source": [ |
36 | | - "The first step is to define a function that takes a parameter that is a callable, and applies it to itself.\n", |
37 | | - "```\n", |
38 | | - " lambda f: f(f)\n", |
39 | | - "```\n", |
40 | 71 | "The second step is to define a lambda function that takes a single `int` parameter and computes the factorial of that integer. Hwever, it uses a function `F` that is provided from context.\n", |
41 | 72 | "```\n", |
42 | 73 | " lambda n: 1 if n == 0 else n*F(F)(n - 1)\n", |
43 | 74 | "```\n", |
44 | | - "This function `F` is a function that takes an integer as " |
| 75 | + "This function `F` is a function that takes a function as an argument. When that function `F` is applied to itself, it returns an `int`, possibly only after multiple recursive calls." |
45 | 76 | ] |
46 | 77 | }, |
47 | 78 | { |
48 | 79 | "cell_type": "code", |
49 | | - "execution_count": null, |
50 | | - "id": "18509fdb-7d14-4bd4-aa55-f6538ebb5f66", |
51 | | - "metadata": {}, |
52 | | - "outputs": [], |
53 | | - "source": [] |
54 | | - }, |
55 | | - { |
56 | | - "cell_type": "code", |
57 | | - "execution_count": 5, |
| 80 | + "execution_count": 3, |
58 | 81 | "id": "5f8686ba-d202-4af1-992c-80dad5245fc5", |
59 | 82 | "metadata": {}, |
60 | 83 | "outputs": [ |
61 | 84 | { |
62 | | - "data": { |
63 | | - "text/plain": [ |
64 | | - "120" |
65 | | - ] |
66 | | - }, |
67 | | - "execution_count": 5, |
68 | | - "metadata": {}, |
69 | | - "output_type": "execute_result" |
| 85 | + "name": "stdout", |
| 86 | + "output_type": "stream", |
| 87 | + "text": [ |
| 88 | + "1\n", |
| 89 | + "1\n", |
| 90 | + "2\n", |
| 91 | + "6\n", |
| 92 | + "24\n", |
| 93 | + "120\n" |
| 94 | + ] |
70 | 95 | } |
71 | 96 | ], |
72 | 97 | "source": [ |
73 | | - "(lambda f: f(f)) (lambda F: lambda n: 1 if n == 0 else n*F(F)(n - 1))(5)" |
| 98 | + "for i in range(6):\n", |
| 99 | + " print((lambda f: f(f)) (lambda F: lambda n: 1 if n == 0 else n*F(F)(n - 1))(i))" |
74 | 100 | ] |
75 | 101 | }, |
76 | 102 | { |
77 | | - "cell_type": "code", |
78 | | - "execution_count": 8, |
79 | | - "id": "9f501593-4fc9-4da5-b3c3-5df4ae8631e5", |
| 103 | + "cell_type": "markdown", |
| 104 | + "id": "06fbb197-1a9f-458c-a7a6-ab27087e9d71", |
80 | 105 | "metadata": {}, |
81 | | - "outputs": [], |
82 | 106 | "source": [ |
83 | | - "b = (lambda F: F(F)) (lambda f: lambda n: 1 if n == 0 else n*f(f)(n - 1))" |
| 107 | + "Another example of a function that can be implemented recursively is the Fibonnaci function." |
84 | 108 | ] |
85 | 109 | }, |
86 | 110 | { |
87 | 111 | "cell_type": "code", |
88 | | - "execution_count": 15, |
89 | | - "id": "e800cc8e-7b3e-4477-a8bf-8266fa9dc0a6", |
| 112 | + "execution_count": 4, |
| 113 | + "id": "f65726d6-7f4f-45aa-ad0e-92fd0eb26309", |
90 | 114 | "metadata": {}, |
91 | 115 | "outputs": [ |
92 | 116 | { |
93 | | - "data": { |
94 | | - "text/plain": [ |
95 | | - "120" |
96 | | - ] |
97 | | - }, |
98 | | - "execution_count": 15, |
99 | | - "metadata": {}, |
100 | | - "output_type": "execute_result" |
| 117 | + "name": "stdout", |
| 118 | + "output_type": "stream", |
| 119 | + "text": [ |
| 120 | + "1\n", |
| 121 | + "1\n", |
| 122 | + "2\n", |
| 123 | + "3\n", |
| 124 | + "5\n", |
| 125 | + "8\n", |
| 126 | + "13\n", |
| 127 | + "21\n", |
| 128 | + "34\n", |
| 129 | + "55\n", |
| 130 | + "89\n" |
| 131 | + ] |
101 | 132 | } |
102 | 133 | ], |
103 | 134 | "source": [ |
104 | | - "b(5)" |
| 135 | + "for i in range(11):\n", |
| 136 | + " print((lambda f: f(f))(lambda F: lambda n: 1 if n <= 1 else F(F)(n - 1) + F(F)(n - 2))(i))" |
105 | 137 | ] |
106 | 138 | }, |
107 | 139 | { |
108 | 140 | "cell_type": "code", |
109 | | - "execution_count": 16, |
110 | | - "id": "269c9ad8-b5c2-4465-b14d-8ba38325b3ac", |
| 141 | + "execution_count": 5, |
| 142 | + "id": "ac699583-0a52-449e-a1ba-7ee5e664eb29", |
111 | 143 | "metadata": {}, |
112 | | - "outputs": [], |
| 144 | + "outputs": [ |
| 145 | + { |
| 146 | + "name": "stdout", |
| 147 | + "output_type": "stream", |
| 148 | + "text": [ |
| 149 | + "4.31 ms ± 431 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" |
| 150 | + ] |
| 151 | + } |
| 152 | + ], |
113 | 153 | "source": [ |
114 | | - "F = lambda f: lambda n: 1 if n == 0 else n*f(f)(n - 1)" |
| 154 | + "%timeit (lambda f: f(f))(lambda F: lambda n: 1 if n <= 1 else F(F)(n - 1) + F(F)(n - 2))(20)" |
115 | 155 | ] |
116 | 156 | }, |
117 | 157 | { |
118 | 158 | "cell_type": "code", |
119 | | - "execution_count": 17, |
120 | | - "id": "9346d8d1-d5b4-4a1d-9c10-fefd96dc80b0", |
| 159 | + "execution_count": 6, |
| 160 | + "id": "884b2dfe-dad6-4e73-93fd-9f8dca2998b2", |
121 | 161 | "metadata": {}, |
122 | 162 | "outputs": [], |
123 | 163 | "source": [ |
124 | | - "b = F(F)" |
| 164 | + "def fib(n: int) -> int:\n", |
| 165 | + " if n < 2:\n", |
| 166 | + " return 1\n", |
| 167 | + " else:\n", |
| 168 | + " return fib(n - 1) + fib(n - 2)" |
125 | 169 | ] |
126 | 170 | }, |
127 | 171 | { |
128 | 172 | "cell_type": "code", |
129 | | - "execution_count": null, |
130 | | - "id": "a65c680c-0f50-461d-b992-e84176b82729", |
131 | | - "metadata": {}, |
132 | | - "outputs": [], |
133 | | - "source": [] |
134 | | - }, |
135 | | - { |
136 | | - "cell_type": "code", |
137 | | - "execution_count": 18, |
138 | | - "id": "2a9ee0a7-85e2-400f-81cc-e05bccde8dd3", |
| 173 | + "execution_count": 7, |
| 174 | + "id": "6ff8db37-91c4-4c52-8be4-6529e6b818cb", |
139 | 175 | "metadata": {}, |
140 | 176 | "outputs": [ |
141 | 177 | { |
142 | | - "data": { |
143 | | - "text/plain": [ |
144 | | - "120" |
145 | | - ] |
146 | | - }, |
147 | | - "execution_count": 18, |
148 | | - "metadata": {}, |
149 | | - "output_type": "execute_result" |
| 178 | + "name": "stdout", |
| 179 | + "output_type": "stream", |
| 180 | + "text": [ |
| 181 | + "1.15 ms ± 81.1 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n" |
| 182 | + ] |
150 | 183 | } |
151 | 184 | ], |
152 | 185 | "source": [ |
153 | | - "b(5)" |
| 186 | + "%timeit fib(20)" |
154 | 187 | ] |
155 | 188 | }, |
156 | 189 | { |
157 | | - "cell_type": "code", |
158 | | - "execution_count": null, |
159 | | - "id": "f65726d6-7f4f-45aa-ad0e-92fd0eb26309", |
| 190 | + "cell_type": "markdown", |
| 191 | + "id": "6dcc5b52-b40f-4d48-8f39-362f8e3544f3", |
160 | 192 | "metadata": {}, |
161 | | - "outputs": [], |
162 | | - "source": [] |
| 193 | + "source": [ |
| 194 | + "It is clear that the non-lambda recursive implementation is significantly faster, so recursion with lambda functions is merely a curiosity to test your understanding of Python." |
| 195 | + ] |
163 | 196 | } |
164 | 197 | ], |
165 | 198 | "metadata": { |
|
0 commit comments