<?xml version="1.0" encoding="utf-8"?>

<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
	<channel>
		<title>Форум программистов и сисадминов Киберфорум - Блоги - Catstail</title>
		<link>https://www.cyberforum.ru/blogs/226808/</link>
		<description>КиберФорум - форум программистов, системных администраторов, администраторов баз данных, компьютерный форум, форум по электронике и бытовой технике, обсуждение софта. Бесплатная помощь в решении задач по программированию и наукам, решение проблем с компьютером, операционными системам</description>
		<language>ru</language>
		<lastBuildDate>Mon, 28 Sep 2026 10:43:46 GMT</lastBuildDate>
		<generator>vBulletin</generator>
		<ttl>60</ttl>
		<image>
			<url>https://www.cyberforum.ru//cyberstatic.net/images/misc/rss.jpg</url>
			<title>Форум программистов и сисадминов Киберфорум - Блоги - Catstail</title>
			<link>https://www.cyberforum.ru/blogs/226808/</link>
		</image>
		<item>
			<title>Некоторые соображения о массовом сознании</title>
			<link>https://www.cyberforum.ru/blogs/226808/8596.html</link>
			<pubDate>Sun, 30 Jun 2024 15:59:17 GMT</pubDate>
			<description>Нейросеть - это грубая модель человеческого мозга... Читатели несомненно встречали эту фразу...</description>
			<content:encoded><![CDATA[<div>Нейросеть - это грубая модель человеческого мозга... Читатели несомненно встречали эту фразу многократно. Наблюдая современных студентов (и, к сожалению, не только студентов) я вынужден констатировать обратное: это мозг - модель нейросети, а не наоборот. Нейросеть прекрасно &quot;запоминает&quot;, но практически не способна к критическому анализу. Так и мозг некоторых &quot;будущих программистов&quot;. Вот пара развёрнутых примеров.<br />
<br />
<b>Факториал</b> <br />
<br />
Как хорошо известно всем n! - это произведение всех целых чисел от 1 до n. Это очень важная целочисленная функция, которая находит широчайшее применение в самых разных разделах математики. <br />
<br />
Как вычислять факториал? Исходя из данного выше определения, у разумного человека должен &quot;родиться&quot; следующий код:<br />
<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="189100764"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="189100764" style="height: 126px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
</pre></td><td class="de1"><pre class="de1"><span class="kw4">int</span> fact<span class="br0">&#40;</span><span class="kw4">int</span> n<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw4">int</span> r<span class="sy0">=</span><span class="nu0">1</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span><span class="kw4">int</span> i<span class="sy0">=</span><span class="nu0">2</span><span class="sy0">;</span> i<span class="sy0">&lt;=</span>n<span class="sy0">;</span> i<span class="sy0">++</span><span class="br0">&#41;</span> r<span class="sy0">*=</span>i<span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw1">return</span> r<span class="sy0">;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Да, этот код будет работать только до значений n, не превышающих 10, но сейчас речь не об этом. Если не нужна абсолютная точность (и достаточно 16 значащих цифр), то можно перейти к типу double. Всё это понятно. Но почему же очень многие студенты вычисляют факториал, используя рекурсию:<br />
<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="245449465"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="245449465" style="height: 142px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
</pre></td><td class="de1"><pre class="de1"><span class="kw4">int</span> fact<span class="br0">&#40;</span><span class="kw4">int</span> n<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp;<span class="kw1">if</span> <span class="br0">&#40;</span>n <span class="sy0">==</span> <span class="nu0">0</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">1</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp;<span class="kw1">else</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> n<span class="sy0">*</span>fact<span class="br0">&#40;</span>n<span class="sy0">-</span><span class="nu0">1</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Вполне очевидно, что рекурсивный код менее эффективен. Так почему многие и многие (и ChatGPT ?) используют этот код?<br />
Я не вижу другого объяснения кроме самого очевидного: когда студентам &quot;объясняют рекурсию&quot;, то в качестве одного из примеров (если не самого первого!) приводят расположенный выше код. И что же? Нейросеть обучается - в ней прочно &quot;прожигается&quot; пара &quot;факториал - рекурсия&quot;. Всё. Акт обучения завершён. Теперь обучаемый будет программировать по принципу <s>&quot;мы говорим Ленин, подразумеваем партия&quot;</s> &quot;мы говорим факториал, подразумеваем рекурсия&quot;...<br />
<br />
Читатели могут &quot;пошерстить&quot; разделы Форума (посвященные разным языкам) и убедиться, что &quot;обучение работает&quot;.<br />
<br />
Чтобы не заканчивать раздел негативом, приведу рациональный совет. Если вам, читатель, нужно интенсивно использовать факториал (скажем, для аргументов от нуля до 20), то самое разумное решение будет таким:<br />
<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="17374409"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="17374409" style="height: 158px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
</pre></td><td class="de1"><pre class="de1">&nbsp; &nbsp;<span class="kw4">double</span> fact<span class="br0">&#91;</span><span class="nu0">21</span><span class="br0">&#93;</span><span class="sy0">;</span>
&nbsp; &nbsp;
&nbsp; &nbsp;<span class="coMULTI">/*...*/</span>
&nbsp;
&nbsp; &nbsp;fact<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="sy0">=</span><span class="nu0">1</span><span class="sy0">;</span>
&nbsp; &nbsp;<span class="kw1">for</span> <span class="br0">&#40;</span><span class="kw4">int</span> i<span class="sy0">=</span><span class="nu0">1</span><span class="sy0">;</span> i<span class="sy0">&lt;=</span><span class="nu0">20</span><span class="sy0">;</span> i<span class="sy0">++</span><span class="br0">&#41;</span> fact<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">=</span>i<span class="sy0">*</span>fact<span class="br0">&#91;</span>i<span class="sy0">-</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="sy0">;</span>
&nbsp;
&nbsp; &nbsp;<span class="coMULTI">/*...*/</span></pre></td></tr></table></div></td></tr></tbody></table></div>Теперь в любой формуле, содержащей факториал, пишите не fact(k), а fact[k]. Будет значительно быстрее, поверьте! (Замечание для пуристов: да, этот код использует значение факториала с плавающей точкой, т.е. с погрешностью. Если нужно представление без погрешности, то вместо double придётся использовать соответствующий тип.)<br />
<br />
<b>i++  vs ++i</b><br />
<br />
Не так давно я стал замечать, что появились нонкорформисты, которые стали оператор цикла записывать так:<br />
<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="33938248"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="33938248" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1"><span class="kw1">for</span> <span class="br0">&#40;</span><span class="kw4">int</span> i<span class="sy0">=</span><span class="nu0">1</span><span class="sy0">;</span> i<span class="sy0">&lt;</span><span class="nu0">20</span><span class="sy0">;</span> <span class="sy0">++</span>i<span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Я спросил одного, а почему не &quot;i++&quot;? Он ответил, что &quot;так будет работать быстрее&quot;. Ответ меня изумил. Но &quot;чем чёрт не шутит&quot;... Я решил изучить вопрос. Ответ оказался не столь однозначным, как в случае факториала.<br />
<br />
Действительно, накладные расходы на префиксную форму в вот таком операторе:<br />
<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="169334138"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="169334138" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">&nbsp; x<span class="sy0">=</span>y<span class="sy0">+</span>t<span class="sy0">*</span><span class="br0">&#40;</span><span class="sy0">++</span>w<span class="br0">&#41;</span><span class="sy0">+</span>r<span class="sy0">;</span></pre></td></tr></table></div></td></tr></tbody></table></div>будут меньше, чем в таком:<br />
<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="780223294"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="780223294" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">&nbsp; x<span class="sy0">=</span>y<span class="sy0">+</span>t<span class="sy0">*</span><span class="br0">&#40;</span>w<span class="sy0">++</span><span class="br0">&#41;</span><span class="sy0">+</span>r<span class="sy0">;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Почему? Потому, что в первом случае можно смело увеличить w, а затем вычислять выражение. А во втором случае будет посложнее... <br />
<br />
В языках с &quot;сишным&quot; синтаксисом не зря придуманы префиксная и постфиксная формы автоувеличения. Иногда (по смыслу) нужна префиксная, иногда постфиксная.  А для того, чтобы выбрать, нужен акт размышления. Но <s>нейросеть</s>  неокрепшие мозги на это не способны. Гораздо проще запомнить &quot;рекомендацию&quot;, что префиксное автоувеличение  работает быстрее постфиксного (и должно применяться вместо постфиксного).<br />
<br />
Давайте рассмотрим следующий сишный код:<br />
<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="297085603"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="297085603" style="height: 110px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
</pre></td><td class="de1"><pre class="de1">&nbsp; <span class="kw4">int</span> i<span class="sy0">;</span>
&nbsp; 
&nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span>i<span class="sy0">=</span><span class="nu0">0</span><span class="sy0">;</span> i<span class="sy0">&lt;</span><span class="nu0">10</span><span class="sy0">;</span> i<span class="sy0">++</span><span class="br0">&#41;</span> <span class="kw3">printf</span><span class="br0">&#40;</span><span class="st0">&quot;%d<span class="es1">\n</span>&quot;</span><span class="sy0">,</span>i<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; 
&nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span>i<span class="sy0">=</span><span class="nu0">10</span><span class="sy0">;</span> i<span class="sy0">&lt;</span><span class="nu0">20</span><span class="sy0">;</span> <span class="sy0">++</span>i<span class="br0">&#41;</span> <span class="kw3">printf</span><span class="br0">&#40;</span><span class="st0">&quot;%d<span class="es1">\n</span>&quot;</span><span class="sy0">,</span>i<span class="br0">&#41;</span><span class="sy0">;</span></pre></td></tr></table></div></td></tr></tbody></table></div>После трансляции (dev c++ 32бит) это породит следующий <br />
ассемблерный код:<br />
<br />
<div class="codeblock"><table class="asm"><thead><tr><td colspan="2" id="950547242"  class="head">Assembler</td></tr></thead><tbody><tr class="li1"><td><div id="950547242" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="de1"><pre class="de1">LM3<span class="sy1">:</span>
&nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw6">DWORD</span> PTR <span class="br0">&#91;</span><span class="kw4">ebp</span><span class="sy1">-</span><span class="nu0">4</span><span class="br0">&#93;</span><span class="sy1">,</span> <span class="nu0">0</span>&nbsp; &nbsp; &nbsp;# i<span class="sy1">,</span>
L2<span class="sy1">:</span>
&nbsp; &nbsp; <span class="kw1">cmp</span> <span class="kw6">DWORD</span> PTR <span class="br0">&#91;</span><span class="kw4">ebp</span><span class="sy1">-</span><span class="nu0">4</span><span class="br0">&#93;</span><span class="sy1">,</span> <span class="nu0">9</span>&nbsp; &nbsp; &nbsp;# i<span class="sy1">,</span>
&nbsp; &nbsp; <span class="kw1">jg</span>&nbsp; L3&nbsp; &nbsp;#<span class="sy1">,</span>
&nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw4">eax</span><span class="sy1">,</span> <span class="kw6">DWORD</span> PTR <span class="br0">&#91;</span><span class="kw4">ebp</span><span class="sy1">-</span><span class="nu0">4</span><span class="br0">&#93;</span>&nbsp; &nbsp;# i<span class="sy1">,</span> i
&nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw6">DWORD</span> PTR <span class="br0">&#91;</span><span class="kw4">esp</span><span class="sy1">+</span><span class="nu0">4</span><span class="br0">&#93;</span><span class="sy1">,</span> <span class="kw4">eax</span>&nbsp; &nbsp;#<span class="sy1">,</span> i
&nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw6">DWORD</span> PTR <span class="br0">&#91;</span><span class="kw4">esp</span><span class="br0">&#93;</span><span class="sy1">,</span> OFFSET <span class="kw5">FLAT</span><span class="sy1">:</span>LC0&nbsp; &nbsp; &nbsp;#<span class="sy1">,</span>
&nbsp; &nbsp; <span class="kw1">call</span>&nbsp; &nbsp; _printf &nbsp;#
&nbsp; &nbsp; <span class="kw1">lea</span> <span class="kw4">eax</span><span class="sy1">,</span> <span class="br0">&#91;</span><span class="kw4">ebp</span><span class="sy1">-</span><span class="nu0">4</span><span class="br0">&#93;</span>&nbsp; &nbsp; &nbsp;# tmp75<span class="sy1">,</span>
&nbsp; &nbsp; <span class="kw1">inc</span> <span class="kw6">DWORD</span> PTR <span class="br0">&#91;</span><span class="kw4">eax</span><span class="br0">&#93;</span> &nbsp;# i &nbsp;i<span class="sy1">++</span> !!!
&nbsp; &nbsp; <span class="kw1">jmp</span> L2&nbsp; &nbsp;#
L3<span class="sy1">:</span>
<span class="sy1">.</span>stabn <span class="nu0">68</span><span class="sy1">,</span><span class="nu0">0</span><span class="sy1">,</span><span class="nu0">10</span><span class="sy1">,</span>LM4<span class="sy1">-</span>_main
LM4<span class="sy1">:</span>
&nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw6">DWORD</span> PTR <span class="br0">&#91;</span><span class="kw4">ebp</span><span class="sy1">-</span><span class="nu0">4</span><span class="br0">&#93;</span><span class="sy1">,</span> <span class="nu0">10</span> &nbsp; &nbsp;# i<span class="sy1">,</span>
L5<span class="sy1">:</span>
&nbsp; &nbsp; <span class="kw1">cmp</span> <span class="kw6">DWORD</span> PTR <span class="br0">&#91;</span><span class="kw4">ebp</span><span class="sy1">-</span><span class="nu0">4</span><span class="br0">&#93;</span><span class="sy1">,</span> <span class="nu0">19</span> &nbsp; &nbsp;# i<span class="sy1">,</span>
&nbsp; &nbsp; <span class="kw1">jg</span>&nbsp; L6&nbsp; &nbsp;#<span class="sy1">,</span>
&nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw4">eax</span><span class="sy1">,</span> <span class="kw6">DWORD</span> PTR <span class="br0">&#91;</span><span class="kw4">ebp</span><span class="sy1">-</span><span class="nu0">4</span><span class="br0">&#93;</span>&nbsp; &nbsp;# i<span class="sy1">,</span> i
&nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw6">DWORD</span> PTR <span class="br0">&#91;</span><span class="kw4">esp</span><span class="sy1">+</span><span class="nu0">4</span><span class="br0">&#93;</span><span class="sy1">,</span> <span class="kw4">eax</span>&nbsp; &nbsp;#<span class="sy1">,</span> i
&nbsp; &nbsp; <span class="kw1">mov</span> <span class="kw6">DWORD</span> PTR <span class="br0">&#91;</span><span class="kw4">esp</span><span class="br0">&#93;</span><span class="sy1">,</span> OFFSET <span class="kw5">FLAT</span><span class="sy1">:</span>LC0&nbsp; &nbsp; &nbsp;#<span class="sy1">,</span>
&nbsp; &nbsp; <span class="kw1">call</span>&nbsp; &nbsp; _printf &nbsp;#
&nbsp; &nbsp; <span class="kw1">lea</span> <span class="kw4">eax</span><span class="sy1">,</span> <span class="br0">&#91;</span><span class="kw4">ebp</span><span class="sy1">-</span><span class="nu0">4</span><span class="br0">&#93;</span>&nbsp; &nbsp; &nbsp;# tmp77<span class="sy1">,</span>
&nbsp; &nbsp; <span class="kw1">inc</span> <span class="kw6">DWORD</span> PTR <span class="br0">&#91;</span><span class="kw4">eax</span><span class="br0">&#93;</span> &nbsp;# i &nbsp; &nbsp; &nbsp;<span class="sy1">++</span>i !!!
&nbsp; &nbsp; <span class="kw1">jmp</span> L5&nbsp; &nbsp;#
L6<span class="sy1">:</span></pre></td></tr></table></div></td></tr></tbody></table></div>Как можно убедиться, в данном случае умный компилятор не делает разницы между префиксной и постфиксной формами. Так что здесь i++ и ++i не различаются. А к чему же я тогда цепляюсь? К бездумному следованию &quot;советам&quot;.<br />
<br />
<br />
Эти два примера наглядно показывают нейросетевой характер человеческого мышления...</div>

]]></content:encoded>
			<dc:creator>Catstail</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/226808/8596.html</guid>
		</item>
		<item>
			<title>Рейтинг: 5.00. Голосов: 3.Коллекция дурацких вопросов - VII (выражает позицию автора блога, как частного лица)</title>
			<link>https://www.cyberforum.ru/blogs/226808/7935.html</link>
			<pubDate>Sun, 05 Feb 2023 18:20:36 GMT</pubDate>
			<description><![CDATA[Новая коллекция "откровений": 
 
96....]]></description>
			<content:encoded><![CDATA[<div>Новая коллекция &quot;откровений&quot;:<br />
<br />
96. <a href="https://www.cyberforum.ru/python-tasks/thread3041535.html#post16553293"><b><a href="https://www.cyberforum.ru/python-tasks/thread3041535.html#post16553293">https://www.cyberforum.ru/pyth... st16553293</a></b></a><br />
<br />
97. <a href="https://www.cyberforum.ru/c-beginners/thread3041549.html"><b><a href="https://www.cyberforum.ru/c-beginners/thread3041549.html">https://www.cyberforum.ru/c-be... 41549.html</a></b></a><br />
<br />
98. <a href="https://www.cyberforum.ru/python-tasks/thread3041949.html"><b><a href="https://www.cyberforum.ru/python-tasks/thread3041949.html">https://www.cyberforum.ru/pyth... 41949.html</a></b></a><br />
<br />
99. <a href="https://www.cyberforum.ru/python-tasks/thread3046636.html"><b><a href="https://www.cyberforum.ru/python-tasks/thread3046636.html">https://www.cyberforum.ru/pyth... 46636.html</a></b></a><br />
<br />
100. <a href="https://www.cyberforum.ru/python-tasks/thread3046614.html"><b><a href="https://www.cyberforum.ru/python-tasks/thread3046614.html">https://www.cyberforum.ru/pyth... 46614.html</a></b></a>  сам вопрос по форме вполне корректен. Но по содержанию...<br />
<br />
101. <a href="https://www.cyberforum.ru/cpp-beginners/thread3050836.html"><b><a href="https://www.cyberforum.ru/cpp-beginners/thread3050836.html">https://www.cyberforum.ru/cpp-... 50836.html</a></b></a><br />
<br />
102. <a href="https://www.cyberforum.ru/python-tasks/thread3051840.html"><b><a href="https://www.cyberforum.ru/python-tasks/thread3051840.html">https://www.cyberforum.ru/pyth... 51840.html</a></b></a><br />
<br />
103. <a href="https://www.cyberforum.ru/csharp-beginners/thread3052592.html"><b><a href="https://www.cyberforum.ru/csharp-beginners/thread3052592.html">https://www.cyberforum.ru/csha... 52592.html</a></b></a><br />
<br />
104. <a href="https://www.cyberforum.ru/python-tasks/thread3054319.html#post16614345"><b><a href="https://www.cyberforum.ru/python-tasks/thread3054319.html#post16614345">https://www.cyberforum.ru/pyth... st16614345</a></b></a><br />
<br />
105. <a href="https://www.cyberforum.ru/cpp-beginners/thread3058504.html"><b><a href="https://www.cyberforum.ru/cpp-beginners/thread3058504.html">https://www.cyberforum.ru/cpp-... 58504.html</a></b></a><br />
<br />
106. <a href="https://www.cyberforum.ru/python-tasks/thread3059034.html"><b><a href="https://www.cyberforum.ru/python-tasks/thread3059034.html">https://www.cyberforum.ru/pyth... 59034.html</a></b></a><br />
<br />
107. <a href="https://www.cyberforum.ru/python-tasks/thread3059034.html"><b><a href="https://www.cyberforum.ru/python-tasks/thread3059034.html">https://www.cyberforum.ru/pyth... 59034.html</a></b></a> формулировка-то, вроде, нормальная. Но загляните внутрь...<br />
<br />
108. <a href="https://www.cyberforum.ru/python-tasks/thread3061659.html"><b><a href="https://www.cyberforum.ru/python-tasks/thread3061659.html">https://www.cyberforum.ru/pyth... 61659.html</a></b></a><br />
<br />
109. <a href="https://www.cyberforum.ru/python-tasks/thread3066570.html"><b><a href="https://www.cyberforum.ru/python-tasks/thread3066570.html">https://www.cyberforum.ru/pyth... 66570.html</a></b></a><br />
<br />
110. <a href="https://www.cyberforum.ru/python-tasks/thread3066665.html"><b><a href="https://www.cyberforum.ru/python-tasks/thread3066665.html">https://www.cyberforum.ru/pyth... 66665.html</a></b></a> вопрос, вроде бы задан нормально... А вот что там внутри:<br />
<br />
&quot;Пример у меня есть число 32 Мне надо чтоб я допустим его делю на 1 если √ из числа 32/1 = целому чилсу то записать √32, если √32/1 не равен целому числу, то 32 уже делится на 2 и также если√32/2 = целому числу то записать выписать √32/2 если √32/2 не равен целому числу то делить на 3, потом на 5 , потом на 7 потом ( делить на те числа которые под корнем не являются целыми числами)&quot;<br />
<br />
Поток сознания...<br />
<br />
111. <a href="https://www.cyberforum.ru/python-beginners/thread3068006.html"><b><a href="https://www.cyberforum.ru/python-beginners/thread3068006.html">https://www.cyberforum.ru/pyth... 68006.html</a></b></a> - тема названа не очень &quot;уклюже&quot;, но понятно. А вот внутри... Поток сознания:<br />
<br />
&quot;Вопрос следующий: когда идет проверка на число, то если проверку проходит то результаты сравниваются, если нет - возвращается функция main() и программа перезапускается и рандомные числа меняются, а как сделать чтобы прога не перезапускалась. То есть проверку на число не проходит и прога просит снова ввести число но с теми же рандомными числами?&quot;<br />
<br />
112. <a href="https://www.cyberforum.ru/python-tasks/thread3069417.html#post16690222"><b><a href="https://www.cyberforum.ru/python-tasks/thread3069417.html#post16690222">https://www.cyberforum.ru/pyth... st16690222</a></b></a>  с виду - вопрос, как вопрос! Но внутри сидит настоящий перл!<br />
<br />
&quot;... Нужно сделать так, чтобы на вход arr_x(x) и arr_y(y) поступало n. Ну.т.е как-то так, но по другому<br />
(Заранее спасибо за помощь)...&quot;<br />
<br />
113. <a href="https://www.cyberforum.ru/python-pygame/thread3070037.html"><b><a href="https://www.cyberforum.ru/python-pygame/thread3070037.html">https://www.cyberforum.ru/pyth... 70037.html</a></b></a><br />
<br />
114. <a href="https://www.cyberforum.ru/visual-basic/thread3073427.html"><b><a href="https://www.cyberforum.ru/visual-basic/thread3073427.html">https://www.cyberforum.ru/visu... 73427.html</a></b></a> Из формулировки вопроса: &quot;...готовая функция должна выводиться в Picture в нарисованном виде&quot;<br />
<br />
115. <a href="https://www.cyberforum.ru/c-beginners/thread3073476.html"><b><a href="https://www.cyberforum.ru/c-beginners/thread3073476.html">https://www.cyberforum.ru/c-be... 73476.html</a></b></a> Формулировка в меру безумна... А вот что там внутри: &quot;как посчитать символы в вещественных цифрах? (по типу float и double)&quot;<br />
<br />
116. <a href="https://www.cyberforum.ru/python-tasks/thread3073494.html"><b><a href="https://www.cyberforum.ru/python-tasks/thread3073494.html">https://www.cyberforum.ru/pyth... 73494.html</a></b></a> Внутри - поток сознания:<br />
<br />
&quot;Мне нужно когда клиент отправил вопрос на сервер, началось ожидание ответа, когда я запускаю бесконечную функцию while true код клиента зависает и вылетает как это можно реализовать, чтоб я задал вопрос получил ответ да допустим и происходит определённые действия, нет, и действия не произходят?&quot; - синтаксис и орфография сохранены.<br />
<br />
117. <a href="https://www.cyberforum.ru/python/thread3073722.html#post16715777"><b><a href="https://www.cyberforum.ru/python/thread3073722.html#post16715777">https://www.cyberforum.ru/pyth... st16715777</a></b></a><br />
<br />
118. <a href="https://www.cyberforum.ru/python-tasks/thread3076368.html#post16734188"><b><a href="https://www.cyberforum.ru/python-tasks/thread3076368.html#post16734188">https://www.cyberforum.ru/pyth... st16734188</a></b></a><br />
<br />
119. <a href="https://www.cyberforum.ru/python-tasks/thread3076581.html#post16734766"><b><a href="https://www.cyberforum.ru/python-tasks/thread3076581.html#post16734766">https://www.cyberforum.ru/pyth... st16734766</a></b></a></div>

]]></content:encoded>
			<dc:creator>Catstail</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/226808/7935.html</guid>
		</item>
		<item>
			<title>Коллекция дурацких вопросов - VI (выражает позицию автора блога, как частного лица)</title>
			<link>https://www.cyberforum.ru/blogs/226808/7785.html</link>
			<pubDate>Wed, 09 Nov 2022 13:48:19 GMT</pubDate>
			<description>Следующая порция интересных вопросов...  
 
82. *https://www.cyberforum.ru/post16510732.html*...</description>
			<content:encoded><![CDATA[<div>Следующая порция интересных вопросов... <br />
<br />
82. <a href="https://www.cyberforum.ru/post16510732.html"><b><a href="https://www.cyberforum.ru/post16510732.html">https://www.cyberforum.ru/post16510732.html</a></b></a><br />
<br />
&quot;...Прочитал 9 главу в конце книги, но понимаю, что ничего не понимаю... Про функцию Interface_Window ни слова... Максимум, что понял, - написать guide в консоли в нижней половине. Появятся два окна - из первого нужные элементы перетягивать во второе... А дальше темный лес... Проблема в том, как заставить кнопки и поля работать... Киньте ссылки на видео по программам с графическим интерфейсом, пожалуйста!!! <b>Проще смотреть, чем читать...</b>&quot; (Выделение мое - Catstail)<br />
<br />
83.  <a href="https://www.cyberforum.ru/delphi-beginners/thread3032515.html#post16511332"><b><a href="https://www.cyberforum.ru/delphi-beginners/thread3032515.html#post16511332">https://www.cyberforum.ru/delp... st16511332</a></b></a><br />
<br />
&quot;...Здравствуйте, ребят помогите пожалуйста, не могу не как сделать, у меня есть на форми несколько edit,ов<br />
И мне собственно нужно сделать так чтобы если в эдит написали &quot;N/A&quot; он не выводил в мемо &quot;&lt;N/A&gt;&quot; скобки а просто вывил &quot;N/A&quot; а если есть текст в эдит он писал &quot;&lt;примерно&gt;&quot; уже в скобках, пробовал сделать так...&quot;<br />
<br />
84. <a href="https://www.cyberforum.ru/python-tasks/thread3033262.html"><b><a href="https://www.cyberforum.ru/python-tasks/thread3033262.html">https://www.cyberforum.ru/pyth... 33262.html</a></b></a><br />
<br />
&quot;...Натуральный логарифм (формула работает при0&lt; x62):ln(x) = (x−1)−(x−1)22+(x−1)33−(x−1)44+· · ·=∞∑n=1(−1)n−1(x−1)nnЧтобы найти логарифм дляx &gt;2, необходимо представить его в видеln(x) = ln(y·2p) =pln(2) + ln(y), гдеy &lt;2, аpнатуральное число. Чтобынайтиpиy, нужно в цикле делитьxна 2 до тех пор, пока результат больше2. Когда очередной результат деления станет меньше 2, этот результат иестьy, а число делений, за которое он достигнут – этоp. Для проверкииспользовать функциюmath.log(x Помогите решить на питоне&quot;<br />
<br />
85. <a href="https://www.cyberforum.ru/python-beginners/thread3033426.html"><b><a href="https://www.cyberforum.ru/python-beginners/thread3033426.html">https://www.cyberforum.ru/pyth... 33426.html</a></b></a><br />
<br />
86. <a href="https://www.cyberforum.ru/python-beginners/thread3034225.html"><b><a href="https://www.cyberforum.ru/python-beginners/thread3034225.html">https://www.cyberforum.ru/pyth... 34225.html</a></b></a><br />
<br />
Обычно подобная публика формулирует вопрос именно так (не работает if, не работает for и т.п.). Неокрепшие мозги не в состоянии понять простую вещь: на Питоне работают сотни тысяч программистов. И у всех &quot;работает&quot;...<br />
<br />
Из этой же ветки:<br />
<br />
&quot;предположим у нас есть слот 0, и мне его надо связать с названием таблички из массива или как?<br />
а и еще же мне надо очищать таблицу прежде чем вставить у меня есть кнопка, я думаю когда мы уже выбрали в комбобоксе и нажали загрузить то в этой функции aboba() перед запросом очистка тогда таблицы должна быть или оно при загрузке будет само очищаться?&quot;<br />
<br />
Речь отражает мышление...<br />
<br />
87. <a href="https://www.cyberforum.ru/python-tasks/thread3036846.html"><b><a href="https://www.cyberforum.ru/python-tasks/thread3036846.html">https://www.cyberforum.ru/pyth... 36846.html</a></b></a><br />
<br />
<br />
88. <a href="https://www.cyberforum.ru/c-beginners/thread3036951.html"><b><a href="https://www.cyberforum.ru/c-beginners/thread3036951.html">https://www.cyberforum.ru/c-be... 36951.html</a></b></a><br />
<br />
Тут в заголовке все нормально. Но внутри... Предлагается решить уравнение ax+b=0 методом деления отрезка пополам. Более яркого примера педагогического идиотизма я не знаю!<br />
<br />
89. <a href="https://www.cyberforum.ru/vb-net/thread3035293.html"><b><a href="https://www.cyberforum.ru/vb-net/thread3035293.html">https://www.cyberforum.ru/vb-n... 35293.html</a></b></a><br />
<br />
Числовая последовательность задана формулой Ai=2i^2+i+1. Вычислить треугольник<br />
<br />
90. <a href="https://www.cyberforum.ru/python-beginners/thread3036983.html"><b><a href="https://www.cyberforum.ru/python-beginners/thread3036983.html">https://www.cyberforum.ru/pyth... 36983.html</a></b></a><br />
<br />
&quot;...Помогите пожалуйста, нужно 2 переменных, допустим если написал 1 переходишь на 2 скрипт , написал 2 переходишь на 3 скрипт...&quot;<br />
<br />
91.  <a href="https://www.cyberforum.ru/cpp-beginners/thread3037975.html"><b><a href="https://www.cyberforum.ru/cpp-beginners/thread3037975.html">https://www.cyberforum.ru/cpp-... 37975.html</a></b></a><br />
<br />
Используя указатель на функцию, разработайте программу : Вывод на экран разности двух вещественных чисел. Числа запрашиваем у пользователя. <br />
<br />
92. <a href="https://www.cyberforum.ru/cpp-beginners/thread3037987.html"><b><a href="https://www.cyberforum.ru/cpp-beginners/thread3037987.html">https://www.cyberforum.ru/cpp-... 37987.html</a></b></a><br />
<br />
93. <a href="https://www.cyberforum.ru/python-tasks/thread3039072.html#post16541703"><b><a href="https://www.cyberforum.ru/python-tasks/thread3039072.html#post16541703">https://www.cyberforum.ru/pyth... st16541703</a></b></a><br />
<br />
94. <a href="https://www.cyberforum.ru/mathematical-analysis/thread3039886.html"><b><a href="https://www.cyberforum.ru/mathematical-analysis/thread3039886.html">https://www.cyberforum.ru/math... 39886.html</a></b></a> - дичайший поток сознания...<br />
<br />
95. <a href="https://www.cyberforum.ru/python-beginners/thread3041113.html"><b><a href="https://www.cyberforum.ru/python-beginners/thread3041113.html">https://www.cyberforum.ru/pyth... 41113.html</a></b></a></div>

]]></content:encoded>
			<dc:creator>Catstail</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/226808/7785.html</guid>
		</item>
		<item>
			<title>Идиотизм докатился уже и до преподавателей...</title>
			<link>https://www.cyberforum.ru/blogs/226808/7729.html</link>
			<pubDate>Mon, 17 Oct 2022 11:50:31 GMT</pubDate>
			<description>Очень часто малограмотные и не знающие математики студенты называют уравнением следующую...</description>
			<content:encoded><![CDATA[<div>Очень часто малограмотные и не знающие математики студенты называют уравнением следующую конструкцию:<br />
<br />
<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=7759&amp;d=1667108830" rel="Lightbox" id="attachment7759" ><img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=7759&amp;thumb=1&amp;d=1667108830" class="thumbnail" border="0" alt="Нажмите на изображение для увеличения
Название: blog-00.png
Просмотров: 346
Размер:	3.8 Кб
ID:	7759" style="margin: 5px" /></a> <br />
<br />
На самом же деле - это не уравнение, а задание функции f(x) в зависимости от аргумента. Уравнением принято называть равенство вида:<br />
<br />
<img src="https://www.cyberforum.ru/cgi-bin/latex.cgi?f%28x%29%3D0" border="0" alt="https://www.cyberforum.ru/cgi-bin/latex.cgi?f(x)=0" /><br />
<br />
При этом вид f(x) задан и нужно найти одно или более значений аргументов, которые обращают приведенное выше выражение в верное числовое равенство. Например, решением уравнения<br />
<br />
<img src="https://www.cyberforum.ru/cgi-bin/latex.cgi?sin%28x%29%3D0" border="0" alt="https://www.cyberforum.ru/cgi-bin/latex.cgi?sin(x)=0" /><br />
<br />
является, как известно, набор значений:<br />
<br />
<img src="https://www.cyberforum.ru/cgi-bin/latex.cgi?x%3D%5Cpi%2Ak%3B%20k%5Cin%20Z" border="0" alt="https://www.cyberforum.ru/cgi-bin/latex.cgi?x=\pi*k; k\in Z" /><br />
<br />
Я (как модератор) уже не помню сколько раз указывал полуграмотным, что (*) - не уравнение. Но тщетно... Видимо в неокрепших мозгах наличие в выражении знака &quot;=&quot; прочно связано со словом &quot;уравнение&quot; - они вновь и вновь предлагают &quot;решить уравнение&quot; (*). Но сегодня произошло кое-что похуже. Студиозиус выложил картинку из своей методички (она прилагается).  Теперь безграмотными стали т.н. &quot;преподаватели&quot;. Куда мы катимся?</div>


<!-- attachments -->
	<div style="margin-top:10px">

		
			<fieldset class="fieldset">
				<legend>Миниатюры</legend>
				<div style="padding:3px">
				
	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=7735&amp;d=1666007423" target="attachment" rel="Lightbox" id="attachment7735"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=7735&amp;stc=1&amp;thumb=1&amp;d=1666007423" border="0" alt="Нажмите на изображение для увеличения
Название: vb-xx.png
Просмотров: 1016
Размер:	78.7 Кб
ID:	7735" /></a>
	&nbsp;
	

				</div>
			</fieldset>
		
		
		
		

	</div>
<!-- / attachments -->
]]></content:encoded>
			<dc:creator>Catstail</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/226808/7729.html</guid>
		</item>
		<item>
			<title>Коллекция дурацких вопросов - V (выражает позицию автора блога, как частного лица)</title>
			<link>https://www.cyberforum.ru/blogs/226808/7728.html</link>
			<pubDate>Mon, 17 Oct 2022 03:14:24 GMT</pubDate>
			<description>77. https://www.cyberforum.ru/python-tasks/thread3024991.html 
 
как сделать так, чтобы это...</description>
			<content:encoded><![CDATA[<div>77. <a href="https://www.cyberforum.ru/python-tasks/thread3024991.html">https://www.cyberforum.ru/pyth... 24991.html</a><br />
<br />
как сделать так, чтобы это значение добавлялось в словарь через запятую?<br />
<br />
78. <a href="https://www.cyberforum.ru/python-beginners/thread3025672.html">https://www.cyberforum.ru/pyth... 25672.html</a><br />
<br />
79. <a href="https://www.cyberforum.ru/python-beginners/thread3027340.html">https://www.cyberforum.ru/pyth... 27340.html</a><br />
<br />
80. <a href="https://www.cyberforum.ru/python-tasks/thread3029159.html">https://www.cyberforum.ru/pyth... 29159.html</a><br />
<br />
81. <a href="https://www.cyberforum.ru/c-beginners/thread3028607.html">https://www.cyberforum.ru/c-be... 28607.html</a></div>

]]></content:encoded>
			<dc:creator>Catstail</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/226808/7728.html</guid>
		</item>
		<item>
			<title>Коллекция дурацких вопросов - IV (выражает позицию автора блога, как частного лица)</title>
			<link>https://www.cyberforum.ru/blogs/226808/7721.html</link>
			<pubDate>Thu, 13 Oct 2022 03:11:36 GMT</pubDate>
			<description>*Восплачем, братья! Горько восплачем! Ибо смеяться грешно...* :) 
 
 
56. Сделайте пж прогу для...</description>
			<content:encoded><![CDATA[<div><b><font size="2">Восплачем, братья! Горько восплачем! Ибо смеяться грешно...</font></b> :)<br />
<br />
<br />
56. Сделайте пж прогу для полного чайника, без списков, без всего, если не сложно. Вывести минимальное положительное и максимальное отрицательное число.<br />
<br />
<a href="https://www.cyberforum.ru/python-tasks/thread2927832.html">https://www.cyberforum.ru/pyth... 27832.html</a><br />
<br />
57. <a href="https://www.cyberforum.ru/python-tasks/thread2928823.html">https://www.cyberforum.ru/pyth... 28823.html</a> - сейчас налетят защитники и будут доказывать, что автор вопроса имел в виду многопоточность...<br />
<br />
58. Вот еще поток сознания:<br />
<br />
&quot;В функции deliver мысль была, выбрав индекс модели, будет записано его имя сразу вместо a = input, и вызвав delete хотел имея индекс удалить название детали. 2 часа работал и ничего не получилось. ПОМОГИТЕ&quot;<br />
<br />
<a href="https://www.cyberforum.ru/python-beginners/thread2928861.html">https://www.cyberforum.ru/pyth... 28861.html</a><br />
<br />
59. <a href="https://www.cyberforum.ru/c-beginners/thread2929221.html">https://www.cyberforum.ru/c-be... 29221.html</a><br />
<br />
60. <a href="https://www.cyberforum.ru/python-beginners/thread2929323.html">https://www.cyberforum.ru/pyth... 29323.html</a><br />
<br />
61. <a href="https://www.cyberforum.ru/python-beginners/thread2930733.html">https://www.cyberforum.ru/pyth... 30733.html</a><br />
<br />
62. Пример &quot;мышления&quot;:<br />
<br />
Добрый день мне нужно что нажатие клавиши было максимально схожее с обычной клавиатурой или как почитал в интернете что бы кнопка нажималась до обработки виндовс,pyauto gui и Kaybroad и spyoungtech/ahk модули не работают,хотя обычный скрипт ahk в игре работает,хотелось бы узнать как можно это реализовать,в интернете нашел что возможно поможет<br />
напрямую использовать функции WinAPI из библиотек Windows,но не нашел как это реализовать не документации ничего,можете подскажать как можно реализавать?<br />
Игра самп Радмир<br />
<br />
<a href="https://www.cyberforum.ru/python-tasks/thread2930817.html">https://www.cyberforum.ru/pyth... 30817.html</a><br />
<br />
63. <a href="https://www.cyberforum.ru/python-tasks/thread2936431.html">https://www.cyberforum.ru/pyth... 36431.html</a><br />
<br />
64. <a href="https://www.cyberforum.ru/python-tasks/thread2939152.html">https://www.cyberforum.ru/pyth... 39152.html</a><br />
<br />
65. <a href="https://www.cyberforum.ru/geometry/thread2941716.html">https://www.cyberforum.ru/geom... 41716.html</a><br />
<br />
66. <a href="https://www.cyberforum.ru/cpp-beginners/thread2944600.html">https://www.cyberforum.ru/cpp-... 44600.html</a><br />
<br />
67.  А вот это уже &quot;музыка сфер&quot;. Я имею в виду программный код:<br />
<br />
<a href="https://www.cyberforum.ru/python-beginners/thread2954089.html">https://www.cyberforum.ru/pyth... 54089.html</a><br />
<br />
68. <a href="https://www.cyberforum.ru/python-beginners/thread2957590.html">https://www.cyberforum.ru/pyth... 57590.html</a><br />
<br />
69. <a href="https://www.cyberforum.ru/java-beginners/thread2958130.html">https://www.cyberforum.ru/java... 58130.html</a><br />
<br />
70. <a href="https://www.cyberforum.ru/python-tasks/thread2978995.html">https://www.cyberforum.ru/pyth... 78995.html</a><br />
<br />
71. <a href="https://www.cyberforum.ru/python-beginners/thread3001505.html">https://www.cyberforum.ru/pyth... 01505.html</a><br />
<br />
72. <a href="https://www.cyberforum.ru/cpp-beginners/thread3012875.html">https://www.cyberforum.ru/cpp-... 12875.html</a><br />
<br />
73. <a href="https://www.cyberforum.ru/python-beginners/thread3020846.html">https://www.cyberforum.ru/pyth... 20846.html</a><br />
<br />
74. <a href="https://www.cyberforum.ru/cpp-beginners/thread3022066.html">https://www.cyberforum.ru/cpp-... 22066.html</a><br />
<br />
75. <a href="https://www.cyberforum.ru/pc-problem/thread3023129.html">https://www.cyberforum.ru/pc-p... 23129.html</a><br />
<br />
76. <a href="https://www.cyberforum.ru/cpp-beginners/thread3023937.html">https://www.cyberforum.ru/cpp-... 23937.html</a></div>

]]></content:encoded>
			<dc:creator>Catstail</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/226808/7721.html</guid>
		</item>
		<item>
			<title>Коллекция дурацких вопросов - III (выражает позицию автора блога, как частного лица)</title>
			<link>https://www.cyberforum.ru/blogs/226808/7713.html</link>
			<pubDate>Tue, 11 Oct 2022 03:01:04 GMT</pubDate>
			<description>36.  https://www.cyberforum.ru/python-tasks/thread2872084.html#post15709502 
 
Вот вопрос....</description>
			<content:encoded><![CDATA[<div>36.  <a href="https://www.cyberforum.ru/python-tasks/thread2872084.html#post15709502">https://www.cyberforum.ru/pyth... st15709502</a><br />
<br />
Вот вопрос. Сформулирован нормально. Зато внутри - перл!<br />
<br />
Добрый день! помогите, пожалуйста, понять как в python можно для заданого числа получить все возможные варианты перестановок, при условии, что есть ограничение на количество перестановок. К примеру, есть число 4256 и к-во перестановок, что нужно сделать - 2. То есть желаемым результатом будет список вида: 2465, 5642, 6524 и тд...<br />
Как это лучше всего сделать?<br />
<br />
37. <a href="https://www.cyberforum.ru/python-tasks/thread2882045.html#post15762674">https://www.cyberforum.ru/pyth... st15762674</a><br />
<br />
38. <a href="https://www.cyberforum.ru/python-tasks/thread2886048.html">https://www.cyberforum.ru/pyth... 86048.html</a><br />
<br />
39. <a href="https://www.cyberforum.ru/python-tasks/thread2888441.html">https://www.cyberforum.ru/pyth... 88441.html</a><br />
<br />
40. <a href="https://www.cyberforum.ru/cpp-beginners/thread2888676.html">https://www.cyberforum.ru/cpp-... 88676.html</a><br />
<br />
41. <a href="https://www.cyberforum.ru/python-beginners/thread2889773.html">https://www.cyberforum.ru/pyth... 89773.html</a><br />
<br />
42. <a href="https://www.cyberforum.ru/python-tasks/thread2891520.html#post15808022">https://www.cyberforum.ru/pyth... st15808022</a> (см. пост #3)<br />
<br />
43. <a href="https://www.cyberforum.ru/python-tasks/thread2896760.html">https://www.cyberforum.ru/pyth... 96760.html</a><br />
<br />
44. <a href="https://www.cyberforum.ru/cpp-beginners/thread2898058.html">https://www.cyberforum.ru/cpp-... 98058.html</a><br />
<br />
&quot;написать функцию которая возвращает длину участка в начале первой строки которая не соответствует маске входные данные две строки возвращает длину участка в начале первой строки которая не содержит ни одного символа из второй строки&quot;<br />
<br />
45. <a href="https://www.cyberforum.ru/c-beginners/thread2896102.html">https://www.cyberforum.ru/c-be... 96102.html</a><br />
<br />
46. <a href="https://www.cyberforum.ru/python-beginners/thread2898519.html">https://www.cyberforum.ru/pyth... 98519.html</a><br />
<br />
47. <a href="https://www.cyberforum.ru/python-tasks/thread2899435.html">https://www.cyberforum.ru/pyth... 99435.html</a><br />
<br />
48. <a href="https://www.cyberforum.ru/cpp-beginners/thread2900045.html">https://www.cyberforum.ru/cpp-... 00045.html</a><br />
<br />
49. <a href="https://www.cyberforum.ru/lua/thread2901399.html">https://www.cyberforum.ru/lua/thread2901399.html</a><br />
<br />
50. <a href="https://www.cyberforum.ru/python-beginners/thread2901326.html">https://www.cyberforum.ru/pyth... 01326.html</a><br />
<br />
51. Здрасте, совсем ни че не знаю. Я вот сижу и думаю, как сделать так, чтоб код нашел сумму всех переменных. И если в этих переменных одинаковое значение, то он воспринимал их как одно целое.<br />
пример.<br />
2<br />
2<br />
3<br />
4<br />
5<br />
2 + 3 + 4 + 5.<br />
ну или же<br />
2<br />
3<br />
4<br />
4<br />
5<br />
2 + 3 + 4 +5.<br />
допустим 2 = значение переменной a, 3 = переменной b и т.д<br />
<br />
<a href="https://www.cyberforum.ru/cpp-beginners/thread2909817.html"><b>отсюда</b></a><br />
<br />
52. <a href="https://www.cyberforum.ru/javascript-beginners/thread2916419.html">https://www.cyberforum.ru/java... 16419.html</a><br />
<br />
53. <a href="https://www.cyberforum.ru/electronics/thread2868982.html">https://www.cyberforum.ru/elec... 68982.html</a> - От Павла Федосеева.<br />
<br />
54. <a href="https://www.cyberforum.ru/python-tasks/thread2926791.html">https://www.cyberforum.ru/pyth... 26791.html</a><br />
<br />
55. <a href="https://www.cyberforum.ru/cpp-beginners/thread2927489.html">https://www.cyberforum.ru/cpp-... 27489.html</a></div>

]]></content:encoded>
			<dc:creator>Catstail</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/226808/7713.html</guid>
		</item>
		<item>
			<title>Коллекция дурацких вопросов - II (выражает позицию автора блога, как частного лица)</title>
			<link>https://www.cyberforum.ru/blogs/226808/7711.html</link>
			<pubDate>Sun, 09 Oct 2022 15:04:42 GMT</pubDate>
			<description>18.  https://www.cyberforum.ru/python-db/thread2848958.html 
  
Напишите пожалуйста БД которую...</description>
			<content:encoded><![CDATA[<div>18.  <a href="https://www.cyberforum.ru/python-db/thread2848958.html">https://www.cyberforum.ru/pyth... 48958.html</a><br />
 <br />
Напишите пожалуйста БД которую можно обучить решать задачи, в процессе использования<br />
Помогите пожалуйста сделать БД которую можно обучить решать задачи, в процессе ее использования, чтобы например ввел ей формулу, она запомнила и потом решила по ней.<br />
<br />
19. <a href="https://www.cyberforum.ru/cpp-linux/thread2851986.html">https://www.cyberforum.ru/cpp-... 51986.html</a> подскажите пожалуйста как можно реализовать вывод распечаток в зависимости от значения переменной. например, если var=1, то печатаю все printf, если =0 - то что необходимо выборочно.<br />
ps. что-то типо, если набрать в консоли &quot;show_pci&quot; и &quot;show_pci -v&quot;.<br />
<br />
20.  <a href="https://www.cyberforum.ru/python-tasks/thread2852753.html">https://www.cyberforum.ru/pyth... 52753.html</a><br />
Список в списке в списке<br />
Как при помощи for сделать чтобы можно было вводить переменную. И она убирается в список который<br />
находиться в списке и этот список находится в списке. И это можно делать бесконечно. У меня не<br />
получилось это сделать. Спасибо заранее.<br />
<br />
21. <a href="https://www.cyberforum.ru/python-tasks/thread2852968.html">https://www.cyberforum.ru/pyth... 52968.html</a><br />
<br />
22. <a href="https://www.cyberforum.ru/python-beginners/thread2855552.html">https://www.cyberforum.ru/pyth... 55552.html</a><br />
Суть в том что нужно сделать такой функционал чтобы когда пользователь копирует набор символов код заменял на нужную мне строку которую я задам в коде, заменяться должны фразы начинающиеся на 1 или 3, чтобы потом я мог добавить функцию если фраза начинается например на 0x то замена на совершенно другую фразу<br />
<br />
23. <br />
<a href="https://www.cyberforum.ru/java-beginners/thread2855928.html#post15603923">https://www.cyberforum.ru/java... st15603923</a><br />
<br />
24. <a href="https://www.cyberforum.ru/python-beginners/thread2856205.html">https://www.cyberforum.ru/pyth... 56205.html</a><br />
<br />
25. <a href="https://www.cyberforum.ru/python-tasks/thread2856885.html#post15609493">https://www.cyberforum.ru/pyth... st15609493</a><br />
<br />
26. <a href="https://www.cyberforum.ru/python-tasks/thread2858234.html">https://www.cyberforum.ru/pyth... 58234.html</a><br />
<br />
27. <a href="https://www.cyberforum.ru/python-beginners/thread2858698.html">https://www.cyberforum.ru/pyth... 58698.html</a><br />
<br />
28. <a href="https://www.cyberforum.ru/vba/thread2858640.html">https://www.cyberforum.ru/vba/thread2858640.html</a><br />
<br />
30. <a href="https://www.cyberforum.ru/python-beginners/thread2860758.html">https://www.cyberforum.ru/pyth... 60758.html</a><br />
<br />
31. <a href="https://www.cyberforum.ru/python-beginners/thread2864095.html">https://www.cyberforum.ru/pyth... 64095.html</a><br />
<br />
32. <a href="https://www.cyberforum.ru/python-beginners/thread2864204.html">https://www.cyberforum.ru/pyth... 64204.html</a><br />
<br />
33. <a href="https://www.cyberforum.ru/python-web/thread2864661.html">https://www.cyberforum.ru/pyth... 64661.html</a><br />
<br />
34. <a href="https://www.cyberforum.ru/cpp-beginners/thread2865283.html">https://www.cyberforum.ru/cpp-... 65283.html</a><br />
<br />
35. <a href="https://www.cyberforum.ru/python-beginners/thread2866486.html">https://www.cyberforum.ru/pyth... 66486.html</a><br />
<br />
<b>Продолжение следует</b></div>

]]></content:encoded>
			<dc:creator>Catstail</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/226808/7711.html</guid>
		</item>
		<item>
			<title>Коллекция дурацких вопросов - I (выражает позицию автора блога, как частного лица)</title>
			<link>https://www.cyberforum.ru/blogs/226808/7710.html</link>
			<pubDate>Sun, 09 Oct 2022 05:51:19 GMT</pubDate>
			<description>Решил перенести коллекцию из административного раздела сюда: 
 
1. http://www.cyberforum.ru/?...</description>
			<content:encoded><![CDATA[<div>Решил перенести коллекцию из административного раздела сюда:<br />
<br />
1. <a href="http://www.cyberforum.ru/">http://www.cyberforum.ru/</a><br />
Немного запутался. у меня есть переменная int i - индекс массива. Есть малый цикл - берется значение из<br />
массива за определенное время - допустим, 100 миллисек. Это работает. Дальше я хочу сделать большой цикл<br />
через Listener. переменная i изменилась - снова запускается малый цикл. Но все примеры сводятся к кнопкам,<br />
положению мыши и т.д. Как это сделать?<br />
<br />
2. <a href="http://www.cyberforum.ru/??">http://www.cyberforum.ru/??</a><br />
Как верно прописать условие<br />
(str(h) + ':' if h else '')<br />
Переменная h может быть не объявлена, может наоборот. То есть проверить на наличие переменной<br />
<br />
3. <a href="http://www.cyberforum.ru/pytho">http://www.cyberforum.ru/pytho</a>... 52511.html<br />
Как в питоне сделать функцию изменяющуюся во времени<br />
Я пытался чтобы время было как разность времени до цикла и в цикле , но дата это не переменная флоат.<br />
В интернете нашел только графики изменяющиеся во времени, есть ли путь преобразования типа даты<br />
в флоат?<br />
<br />
4. <a href="https://www.cyberforum.ru/python-beginners/thread2585221.html">https://www.cyberforum.ru/pyth... 85221.html</a> Счетчик итераций<br />
При закидывании массивов разной сложности выводит одно и то же, а то и вовсе возвращает 0,<br />
как пофиксить? (вся суть задания состоит в сортировке 3х видов массива и построении графика, вот пытаюсь<br />
вытянуть counter)<br />
<br />
5. <a href="https://www.cyberforum.ru/c-beginners/thread2587273.html">https://www.cyberforum.ru/c-be... 87273.html</a> Программа для написания языка программирования СИ<br />
привет) мне нужна программа на которой нормально можно написать язык программирования СИ ??) чтоб сразу<br />
можно установить и писать))<br />
<br />
6. <a href="https://www.cyberforum.ru/python-beginners/thread2590793.html">https://www.cyberforum.ru/pyth... 90793.html</a><br />
 Написать функцию, которая получает аргументом натуральное число и возвращает его в виде строки<br />
Написать функцию, которая получает аргументом натуральное число и возвращает его в виде строки 5 = x + y<br />
<br />
7.  <a href="https://www.cyberforum.ru/java-beginners/thread2590887.html">https://www.cyberforum.ru/java... 90887.html</a><br />
Сумма двух чисел<br />
Cоздать программу которая читает 2 натуральных чисел и проверяет если сумма этих чисел одинаково.<br />
Кто знает как решить? Буду благодарен!<br />
<br />
8. <a href="https://www.cyberforum.ru/python-beginners/thread2591891.html">https://www.cyberforum.ru/pyth... 91891.html</a><br />
Всем привет)) Подскажите, пожалуйста, как можно сделать так, чтобы пользователь загружал файл с<br />
расширением .docx через кнопку в python (т.е. не в коде прописать конкретный файл)? Можно<br />
какие-нибудь ссылочки, если знаете)<br />
<br />
9. <a href="https://www.cyberforum.ru/c-beginners/thread2761577.html">https://www.cyberforum.ru/c-be... 61577.html</a><br />
 Формат дробных чисел<br />
Здравствуйте, мне нужно, чтобы в программе число выписывалось через точку.<br />
Например 25.36 , 56.78 и тд но у меня это все через запятую т.е. 25,36 , 56,78 итд<br />
можете с этим помочь?<br />
<br />
10. <a href="https://www.cyberforum.ru/c-beginners/thread2761577.html">https://www.cyberforum.ru/c-be... 61577.html</a><br />
Как можно вывести элементы массива в файл в виде треугольников?<br />
<br />
11.  <a href="https://www.cyberforum.ru/cpp-beginners/thread2782027.html">https://www.cyberforum.ru/cpp-... 82027.html</a><br />
почему при минимальной формуле количества перестановок в программе гораздо меньше<br />
почему при минимальной формуле количества перестановок в программе гораздо меньше<br />
Например есть метод выбора вот для него формула перестановок (действий): min:3(n-1),max:1/4*n^2+3(n-1),n-количество элементов.<br />
В программе получается 9 а в формуле с минимальным 27 с максимальным 52,это при 10 элементах.<br />
<br />
12. <a href="https://www.cyberforum.ru/cpp-linux/thread2781111.html">https://www.cyberforum.ru/cpp-... 81111.html</a><br />
Что означает появление командной строки посреди вывода данных в консоль<br />
<br />
13. <a href="https://www.cyberforum.ru/python-tasks/thread2782879.html">https://www.cyberforum.ru/pyth... 82879.html</a><br />
Напишите программу, которая в последовательности натуральных чисел определяет максимальное число, кратное 1.<br />
Программа получает на вход количество чисел в последовательности, а затем сами числа.<br />
В последовательности всегда имеется число, кратное 1. Количество чисел не превышает 1000.<br />
Введённые числа не превышают 30 000.<br />
<br />
14.  <a href="https://www.cyberforum.ru/cpp-beginners/thread2784940.html">https://www.cyberforum.ru/cpp-... 84940.html</a><br />
Объявить функцию в которую можно передать функцию из класса<br />
Здравствуйте, как можно передать в функцию функцию из класса? Точнее каким образом нужно<br />
объявить ф-цию что бы в неё можно передать ф-цию из класса?<br />
<br />
15.  <a href="https://www.cyberforum.ru/cpp-beginners/thread2786697.html">https://www.cyberforum.ru/cpp-... 86697.html</a><br />
Как объявить переменную, чтобы она не удалилась из памяти?<br />
Как объявить переменную, чтобы она не удалилась из памяти?<br />
<br />
16.  <a href="https://www.cyberforum.ru/python-beginners/thread2826113.html">https://www.cyberforum.ru/pyth... 26113.html</a><br />
Цикл for в качестве аргумента функции<br />
Как сделать чтобы функция принимала аргументом сам цикл for? Последовательно подставляла данные из двух списков?<br />
<br />
17.  <a href="https://www.cyberforum.ru/python-beginners/thread2842295.html">https://www.cyberforum.ru/pyth... 42295.html</a><br />
Степень для x<br />
Мне нужно возвести x**n, допустим, 4 и выдать x**4<br />
если написать x = 'x'<br />
это не сработает из-за того что это string.<br />
<br />
<br />
<b>Продолжение следует!</b></div>

]]></content:encoded>
			<dc:creator>Catstail</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/226808/7710.html</guid>
		</item>
		<item>
			<title>Мемоизация в Лиспе</title>
			<link>https://www.cyberforum.ru/blogs/226808/7273.html</link>
			<pubDate>Mon, 13 Sep 2021 17:03:35 GMT</pubDate>
			<description>Моя одноименная статья на Хабре. Пожалуй, несколько тяжеловесная. 
 
*Введение и постановка задачи*...</description>
			<content:encoded><![CDATA[<div>Моя одноименная статья на Хабре. Пожалуй, несколько тяжеловесная.<br />
<br />
<b>Введение и постановка задачи</b><br />
<br />
Если вы ни разу не слышали слово “мемоизация”, то проще всего будет уяснить суть этого понятия на следующем распространенном примере.<br />
<br />
Предположим, в вашу программу входит функция, которая часто вычисляется для одного и того же набора аргументов. В этом случае ускорить вычисления поможет следующий очевидный прием: нужно заранее вычислить значения функции для всех частых наборов аргументов и занести эти значения в какую-либо подходящую структуру хранения (хранилище).<br />
<br />
После чего переработать функцию таким образом:<br />
<br />
- Для “частых” аргументов функция “достает” заранее вычисленные значения из хранилища;<br />
<br />
- Для других аргументов значения честно вычисляются функцией.<br />
<br />
Совершенно очевидно, что такое преобразование увеличит общую скорость вычислений. Причем прирост скорости будет особенно заметен, когда:<br />
<br />
- Область определения функции достаточно узка;<br />
<br />
- Вычисления каждого значения из области определения достаточно затратны.<br />
<br />
Приведенный пример, однако, не слишком впечатляет, поскольку требует переработки кода. Так вот: мемоизация – это преобразование функции (не затрагивающее ее код), дающее новую функцию, которая:<br />
<br />
- Содержит внутреннее хранилище данных ;<br />
<br />
- Получив очередной аргумент/аргументы, проверяет, не вычислялась ли уже функция для этого аргумента/аргументов;<br />
<br />
- Если функция уже вычислялась, результат извлекается из хранилища и возвращается;<br />
<br />
- Если функция для этого аргумента/аргументов еще не вычислялась, то выполняется вычисление, результат с соответствующим ключом запоминается в хранилище и возвращается как результат.<br />
<br />
Идея, как видите, проста. А ее исполнение сильно зависит от языка программирования. И особенно легко реализуется эта идея в интерпретируемом языке, поддерживающим лямбда-функции. Такими языками являются, например, Питон и Лисп.<br />
<br />
Как следует из названия заметки, все наши действия мы будем выполнять в Лиспе. (А в Питоне все уже “сделано до нас”). Я использую HomeLisp, но желающие, надеюсь, смогут перенести эти идеи в любую версию Лиспа без особого труда.<br />
<br />
Давайте рассмотрим пример, ставший классическим – “лобовое” вычисление чисел Фибоначчи, последовательности, имеющей вид:<br />
<br />
F<sub>0</sub>=1, F<sub>1</sub>=1, F<sub>n</sub>=F<sub>n-1</sub>+F<sub>n-2</sub><br />
<br />
Код функции, вычисляющей число Фибоначчи с номером n пишется сразу:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="178016361"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="178016361" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">defun</span> fib <span class="br0">&#40;</span>n<span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">&lt;=</span> n <span class="nu0">1</span><span class="br0">&#41;</span> <span class="nu0">1</span> <span class="br0">&#40;</span>+ <span class="br0">&#40;</span>fib <span class="br0">&#40;</span>- n <span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#40;</span>fib <span class="br0">&#40;</span>- n <span class="nu0">2</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Функция столь же проста, сколь и неэффективна. Если, к примеру, запустить ее с параметром n=20, то возникнет заметная “пауза”. Почему? Ответ на этот вопрос легко получить, если запросить статистику выполнения отдельных функций Лиспа при вычислении. В HomeLisp для этого служит встроенная функция stat. При вычислении двадцатого числа Фибоначчи статистика вызовов получается такой:<br />
<br />
<img src="https://disk.yandex.ru/i/2kwHtO63hu824A" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /><a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=7139&amp;d=1631552307" rel="Lightbox" id="attachment7139" ><img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=7139&amp;thumb=1&amp;d=1631552307" class="thumbnail" border="0" alt="Нажмите на изображение для увеличения
Название: mem-lsp.png
Просмотров: 505
Размер:	4.2 Кб
ID:	7139" style="margin: 5px" /></a><br />
<br />
Для того, чтобы вычислить 20-е число Фибоначчи, потребовалось более двадцати тысяч рекурсивных вызовов нашей fib (не считая такого же количества вычитаний и сравнений)!<br />
<br />
В чем же причина?<br />
<br />
В многократном перевычислении значений функции fib при одних и тех же значениях аргументов. В этом совсем легко убедиться, включив трассировку. При увеличении n количество повторных обращений будет экспоненциально нарастать, что делает приведенный алгоритм крайне неэффективным.<br />
<br />
Известен способ, позволяющий резко ускорить этот код – отказаться от параллельной рекурсии и использовать накопительные параметры (или вообще отказаться от рекурсии и решить задачу чисто итеративно)<br />
<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="916063073"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="916063073" style="height: 174px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">defun</span> fib <span class="br0">&#40;</span>n <span class="sy0">&amp;</span>optional <span class="br0">&#40;</span>c <span class="nu0">1</span><span class="br0">&#41;</span> <span class="br0">&#40;</span>p <span class="nu0">0</span><span class="br0">&#41;</span><span class="br0">&#41;</span> &nbsp;<span class="co1">;; рекурсия</span>
&nbsp; &nbsp;<span class="br0">&#40;</span><span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">zerop</span> n<span class="br0">&#41;</span> c <span class="br0">&#40;</span>fib <span class="br0">&#40;</span>- n <span class="nu0">1</span><span class="br0">&#41;</span> <span class="br0">&#40;</span>+ c p<span class="br0">&#41;</span> c<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp;
<span class="br0">&#40;</span><span class="kw1">defun</span> fib <span class="br0">&#40;</span>n<span class="br0">&#41;</span> <span class="co1">;; итерация</span>
&nbsp; <span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>c <span class="nu0">1</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span>p <span class="nu0">0</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span>tmp <span class="nu0">0</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">dotimes</span> <span class="br0">&#40;</span>i n c<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">setq</span> tmp <span class="br0">&#40;</span>+ c p<span class="br0">&#41;</span> p c c tmp<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Оба эти способа хороши всем, кроме одного – они нарушают “прозрачность” кода. Прямое рекурсивное вычисление легко сопоставляется с математической постановкой задачи. А ускоренные программы требуют анализа – связь этих программ с математической постановкой задачи отнюдь не очевидна. И это – большой недостаток. Ведь программы “читают” не только компиляторы, но и программисты. Прозрачность и понятность кода – ценнейшее качество.<br />
<br />
Теперь мы можем сформулировать задачу. Имеется функция (пока – одного аргумента), нам необходимо построить новую функцию, которая будет “содержать старую функцию внутри”. Эта новая функция должна выполнять следующее:<br />
<br />
- Получив значение аргумента, проверить не вычислялась ли функция с этим аргументом ранее. Если вычислялась, достать из внутреннего хранилища значение функции и вернуть его.<br />
<br />
- Если значение ранее не вычислялось, вычислить его (обратясь к “старой” функции), занести пару (аргумент, значение-функции) во внутреннее хранилище и вернуть вычисленное значение.<br />
<br />
<b>Первая реализация<br />
</b><br />
Начнем реализацию с того, что выберем внутреннее хранилище. Проще всего для первых экспериментов выбрать ассоциативный список. Это классическая структура данных, широко используемая в Лиспе. Ассоциативный список состоит из пар “ключ-значение”. Для получения значения по ключу служит встроенная функция assoc. Она берет на вход список и ключ, а возвращает пару, соответствующую ключу (или nil, если ключ не найден). Извлечь значение из пары должен программист. Почему так неудобно? Разве не проще было бы сразу возвращать значение по ключу? Причина в том, что если возвращать &quot;чистое значение&quot;, то невозможно будет отличить случай отсутствия значения (возврат Nil), от случая, когда Nil является легальным значением.<br />
<br />
Теперь давайте возьмем нашу первую реализацию fib (основанную на математическом определении последовательности Фибоначчи) и доработаем ее в соответствии механизмом мемоизации. Сразу возникнет вопрос: где разместить ассоциативный список (в котором будут храниться результаты вычислений). В теле fib хранить этот список бессмысленно – все локальные переменные при каждом вызове функции создаются заново, а статических переменных в Лиспе нет. Как же быть?<br />
<br />
На помощь придет замыкание - функция с зафиксированными на момент создания значениями ее свободных переменных. Свободная переменная – это переменная, входящая в тело функции, но не входящая в список параметров и не созданной внутри функции с помощью let/let*. Проще всего замыкание в HomeLisp создается заданием функции (с помощью defun) в области действия let-конструкции. Это выглядит так:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="623547654"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="623547654" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>asso <span class="kw1">nil</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp;<span class="br0">&#40;</span><span class="kw1">defun</span> fib <span class="br0">&#40;</span>n<span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">&lt;=</span> n <span class="nu0">1</span><span class="br0">&#41;</span> <span class="nu0">1</span> <span class="br0">&#40;</span>+ <span class="br0">&#40;</span>fib <span class="br0">&#40;</span>- n <span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#40;</span>fib <span class="br0">&#40;</span>- n <span class="nu0">2</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Получившаяся функция fib с виду совсем обычна: ее можно вызвать с одним аргументом и получить правильное значение:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="722930746"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="722930746" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span>fib <span class="nu0">5</span><span class="br0">&#41;</span>
<span class="sy0">==&gt;</span> <span class="nu0">8</span></pre></td></tr></table></div></td></tr></tbody></table></div>Но есть и существенное отличие – теперь у функции имеется контекст (содержащий, естественно, переменную asso). В HomeLisp этот контекст можно увидеть:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="867104713"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="867104713" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span>context 'fib<span class="br0">&#41;</span>
<span class="sy0">==&gt;</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>ASSO <span class="kw1">NIL</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>При этом переменную asso можно менять в теле функции – новые значения будут сохраняться между вызовами. Это именно такое поведение, которое нам требуется. Конструируем замыкание, которое будет сохранять результаты промежуточных вызовов в локальном ассоциативном списке:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="449124684"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="449124684" style="height: 126px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>asso <span class="kw1">nil</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; <span class="br0">&#40;</span><span class="kw1">defun</span> fib <span class="br0">&#40;</span>n<span class="br0">&#41;</span> 
&nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>tmp <span class="br0">&#40;</span><span class="kw1">assoc</span> n asso<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">if</span> tmp <span class="br0">&#40;</span><span class="kw1">cdr</span> tmp<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>r <span class="br0">&#40;</span><span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">&lt;=</span> n <span class="nu0">1</span><span class="br0">&#41;</span> <span class="nu0">1</span> <span class="br0">&#40;</span>+ <span class="br0">&#40;</span>fib <span class="br0">&#40;</span>- n <span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#40;</span>fib <span class="br0">&#40;</span>- n <span class="nu0">2</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span>push <span class="br0">&#40;</span><span class="kw1">cons</span> n r<span class="br0">&#41;</span> asso<span class="br0">&#41;</span> r<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Что внутри? Когда fib получит управление (с конкретным значением n), первым делом выполняется попытка &quot;достать&quot; из ассоциативного списка значение fib(n), используя n как ключ.<br />
<br />
Если попытка успешна, то переменная tmp получит значение соответствующей пары. Остается вернуть результат, взяв cdr этой пары.<br />
<br />
Если же ключа n в ассоциативном списке нет, то смело вычисляем нужное значение (да-да, с той самой параллельной рекурсией) и присваиваем результат переменной r. Добавляем пару (n . r) в ассоциативный список (это делает push) и возвращаем r. Всё!<br />
<br />
Функцию fib можно проверить &quot;в деле&quot;:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="221170208"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="221170208" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span>fib <span class="nu0">10</span><span class="br0">&#41;</span>
<span class="sy0">==&gt;</span> <span class="nu0">89</span></pre></td></tr></table></div></td></tr></tbody></table></div>Если теперь запросить контекст нашей функции, то можно убедиться, что он хранит все промежуточные значения в виде точечных пар:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="368214040"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="368214040" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span>context 'fib<span class="br0">&#41;</span>
<span class="sy0">==&gt;</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>ASSO <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="nu0">10</span> <span class="sy0">.</span> <span class="nu0">89</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="nu0">9</span> <span class="sy0">.</span> <span class="nu0">55</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="nu0">8</span> <span class="sy0">.</span> <span class="nu0">34</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="nu0">7</span> <span class="sy0">.</span> <span class="nu0">21</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="nu0">6</span> <span class="sy0">.</span> <span class="nu0">13</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="nu0">5</span> <span class="sy0">.</span> <span class="nu0">8</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="nu0">4</span> <span class="sy0">.</span> <span class="nu0">5</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="nu0">3</span> <span class="sy0">.</span> <span class="nu0">3</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="nu0">2</span> <span class="sy0">.</span> <span class="nu0">2</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="nu0">0</span> <span class="sy0">.</span> <span class="nu0">1</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="nu0">1</span> <span class="sy0">.</span> <span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Что же, для мемоизации функции нужно всякий раз вручную подобным образом перерабатывать ее код? Конечно, нет. Мы сейчас создадим макро &quot;memoize&quot;, которое будет &quot;брать&quot; обычную функцию и автоматически строить нужное замыкание под прежним именем.<br />
<br />
Макро – это очень хитрая функция Лиспа. Ее вычисление имеет две особенности:<br />
<br />
- ядро Лиспа не вычисляет значения аргументов macro;<br />
<br />
- макро вычисляется в два этапа: на первом этапе строится форма, которая вычисляется на втором этапе (в текущем окружении переменных).<br />
<br />
Теперь понятно, почему я сначала построил рабочее замыкание – мы должны создать макро, которое на первом этапе построит форму, которая, вычислившись на втором этапе, породит нужное замыкание.<br />
<br />
В этом смысле, разработка макро чем-то напоминает web-разработку: мы пишем код, который должен породить другой код с нужным поведением.<br />
<br />
Прежде, чем браться за макро, следует сказать пару слов об одной возможности HomeLisp. Имеется встроенная функция getd, которая обеспечивает доступ к телу любой функции, написанной на Лиспе. Как это работает – показано ниже:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="399456676"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="399456676" style="height: 110px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">defun</span> fib <span class="br0">&#40;</span>n<span class="br0">&#41;</span>
&nbsp; &nbsp;<span class="br0">&#40;</span><span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">&lt;=</span> n <span class="nu0">2</span><span class="br0">&#41;</span> <span class="nu0">1</span> <span class="br0">&#40;</span>+ <span class="br0">&#40;</span>fib <span class="br0">&#40;</span>- n <span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#40;</span>fib <span class="br0">&#40;</span>- n <span class="nu0">2</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp;
<span class="br0">&#40;</span>getd 'fib<span class="br0">&#41;</span>
<span class="sy0">==&gt;</span> <span class="br0">&#40;</span>EXPR <span class="br0">&#40;</span>N<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">IF</span> <span class="br0">&#40;</span><span class="sy0">&lt;=</span> N <span class="nu0">2</span><span class="br0">&#41;</span> <span class="nu0">1</span> <span class="br0">&#40;</span>+ <span class="br0">&#40;</span>FIB <span class="br0">&#40;</span>- N <span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#40;</span>FIB <span class="br0">&#40;</span>- N <span class="nu0">2</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Как можно убедиться, мы получаем доступ к телу fib и к списку параметров. Теперь начнем конструировать макро. Делать это мы будем постепенно.<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="712500797"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="712500797" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">defmacro</span> memoize <span class="br0">&#40;</span>f<span class="br0">&#41;</span>
&nbsp; <span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>body <span class="br0">&#40;</span><span class="kw1">cdr</span> <span class="br0">&#40;</span>getd f<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span>parm <span class="br0">&#40;</span><span class="kw1">cadr</span> <span class="br0">&#40;</span>getd f<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy0">...</span></pre></td></tr></table></div></td></tr></tbody></table></div>Внутри макро создаются две локальные переменные (первого этапа вычисления макро) и им присваиваются значения тела и списка параметров функции, которую мы собираемся мемоизировать. Многоточие означает, что это только начало. Продолжаем:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="496697755"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="496697755" style="height: 94px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">defmacro</span> memoize <span class="br0">&#40;</span>f<span class="br0">&#41;</span>
&nbsp; <span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>body <span class="br0">&#40;</span><span class="kw1">cdr</span> <span class="br0">&#40;</span>getd f<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
<span class="br0">&#40;</span>parm <span class="br0">&#40;</span><span class="kw1">cadr</span> <span class="br0">&#40;</span>getd f<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; `<span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>asso <span class="kw1">nil</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy0">...</span></pre></td></tr></table></div></td></tr></tbody></table></div>Нам нужно, чтобы первый этап вычисления макро оставил после себя замыкание – вот и пишем конструкцию let, предваряя ее обратным апострофом (т.н. обратная блокировка)<br />
<br />
Для тех, кто не знаком с обратной блокировкой, следует сказать несколько слов. Обычный апостроф блокирует вычисление всех символов выражения, а обратный – только тех, перед которыми не стоит запятая. Вот пример:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="315959845"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="315959845" style="height: 94px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>a <span class="nu0">111</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; `<span class="br0">&#40;</span>a <span class="sy0">,</span>a<span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="br0">&#40;</span>A <span class="nu0">111</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Видим, что первый символ A остался без изменения, а второй (перед которым стоит запятая) заменен своим значением.<br />
<br />
Есть еще одна тонкость обратной блокировки, которую следует упомянуть, касается случая, когда значение заменяемого символа является списком. Прежний пример в этом случае будет выглядеть так:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="710561903"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="710561903" style="height: 94px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>a '<span class="br0">&#40;</span><span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; `<span class="br0">&#40;</span>a <span class="sy0">,</span>a<span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="br0">&#40;</span>A <span class="br0">&#40;</span><span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Все вполне логично: символ заменился значением. Но иногда бывает нужно, чтобы символы списка “встали на базовый уровень” (т.е. иногда нужно “убрать” мешающие скобки). Для этого перед нужным символом следует поставить пару “,@”:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="946438697"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="946438697" style="height: 94px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>a '<span class="br0">&#40;</span><span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; `<span class="br0">&#40;</span>a <span class="sy0">,</span>@a<span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="br0">&#40;</span>A <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">1</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Теперь вернемся в наше макро. Дальше должна размещаться конструкция defun:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="559243298"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="559243298" style="height: 174px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">defmacro</span> memoize <span class="br0">&#40;</span>f<span class="br0">&#41;</span>
&nbsp; <span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>body <span class="br0">&#40;</span><span class="kw1">cdr</span> <span class="br0">&#40;</span>getd f<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>parm <span class="br0">&#40;</span><span class="kw1">cadr</span> <span class="br0">&#40;</span>getd f<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp;`<span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>asso <span class="kw1">nil</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">defun</span> <span class="sy0">,</span>f <span class="sy0">,</span>parm
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>tmp <span class="br0">&#40;</span><span class="kw1">assoc</span> <span class="sy0">,</span>@parm asso<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">if</span> tmp <span class="br0">&#40;</span><span class="kw1">cdr</span> tmp<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>r <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="sy0">,</span>@body<span class="br0">&#41;</span> <span class="sy0">,</span>@parm<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>push <span class="br0">&#40;</span><span class="kw1">cons</span> <span class="sy0">,</span>@parm r<span class="br0">&#41;</span> asso<span class="br0">&#41;</span> r<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Рассмотрим более подробно то, что “происходит” внутри. Для нашей функции fib, значением переменной body будет список:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="185998267"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="185998267" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="br0">&#40;</span>N<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">IF</span> <span class="br0">&#40;</span><span class="sy0">&lt;=</span> N <span class="nu0">2</span><span class="br0">&#41;</span> <span class="nu0">1</span> <span class="br0">&#40;</span>+ <span class="br0">&#40;</span>FIB <span class="br0">&#40;</span>- N <span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#40;</span>FIB <span class="br0">&#40;</span>- N <span class="nu0">2</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Значением переменной parm будет список (N), а значением переменной f будет имя нашей функции – fib. А теперь аккуратно подставим значения этих переменных в тело `let. Получим:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="624156759"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="624156759" style="height: 126px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
</pre></td><td class="de1"><pre class="de1">`<span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>asso <span class="kw1">nil</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">defun</span> fib <span class="br0">&#40;</span>N<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>tmp <span class="br0">&#40;</span><span class="kw1">assoc</span> N asso<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">if</span> tmp <span class="br0">&#40;</span><span class="kw1">cdr</span> tmp<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>r <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="br0">&#40;</span>N<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">&lt;=</span> N <span class="nu0">2</span><span class="br0">&#41;</span> <span class="nu0">1</span> <span class="br0">&#40;</span>+ <span class="br0">&#40;</span>FIB <span class="br0">&#40;</span>- N <span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#40;</span>FIB <span class="br0">&#40;</span>- N <span class="nu0">2</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> N<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>push <span class="br0">&#40;</span><span class="kw1">cons</span> N r<span class="br0">&#41;</span> asso<span class="br0">&#41;</span> r <span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Мы присваиваем локальной переменной r значение очередного числа Фибоначчи, затем заносим соответствующую пару в локальный ассоциативный список замыкания и возвращаем значение r как результат.<br />
<br />
Прежде чем двигаться дальше, следует обратить внимание на два тонких момента.<br />
<br />
Для внутреннего вызова “начинки” мемоизируемой функции мы использовали лямбда-выражение. Его формальный параметр – символ N. И этот же символ является и фактическим параметром. Подобная ситуация может вызвать замешательство, но она вполне корректна – значение фактического параметра будет присвоено при вызове нашей будущей функции fib. Если замешательство не прошло, взгляните на пример ниже:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="53587523"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="53587523" style="height: 94px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>x <span class="nu0">4</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp;<span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="br0">&#40;</span>x<span class="br0">&#41;</span> <span class="br0">&#40;</span>* x x<span class="br0">&#41;</span><span class="br0">&#41;</span> x<span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="nu0">16</span></pre></td></tr></table></div></td></tr></tbody></table></div>Второй тонкий момент связан с самим макро. Создавая макро нужно быть предельно осторожным при выборе имен для рабочих переменных. Если второй этап вычисления макро порождает какой-то вычислительный процесс в исходном окружения, и какое-либо внутреннее имя совпадает с именем переменной из окружения, то может произойти т.н. “захват переменной” – крайне неприятный эффект (подробности – в знаменитой книге П.Грэма “ANSI Common Lisp”). К счастью, в нашем случае таких “опасных переменных”, кажется, нет.<br />
<br />
Итак, макро мемоизации готово. Убедимся, что макро работает не только для функции fib. Создадим функцию, которая вычисляет члены последовательности, в которой очередной равен сумме трех предыдущих:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="405421955"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="405421955" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">defun</span> g <span class="br0">&#40;</span>n<span class="br0">&#41;</span> 
&nbsp; &nbsp;<span class="br0">&#40;</span><span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">&lt;</span> n <span class="nu0">2</span><span class="br0">&#41;</span> <span class="nu0">1</span> <span class="br0">&#40;</span>+ <span class="br0">&#40;</span>g <span class="br0">&#40;</span>- n <span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#40;</span>g <span class="br0">&#40;</span>- n <span class="nu0">2</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#40;</span>g <span class="br0">&#40;</span>- n <span class="nu0">3</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Проверим ее работоспособность:<br />
<br />
(g 6)<br />
==&gt; 31<br />
<br />
(g 10)<br />
==&gt; 355<br />
<br />
Функция работает. Попробуем применить к ней наше макро:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="629866997"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="629866997" style="height: 158px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span>memoize g<span class="br0">&#41;</span>
<span class="sy0">==&gt;</span> G
&nbsp;
<span class="br0">&#40;</span>g <span class="nu0">10</span><span class="br0">&#41;</span>
<span class="sy0">==&gt;</span> <span class="nu0">355</span>
&nbsp;
<span class="br0">&#40;</span>context 'g<span class="br0">&#41;</span>
<span class="sy0">==&gt;</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>ASSO <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="nu0">10</span> <span class="sy0">.</span> <span class="nu0">355</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="nu0">9</span> <span class="sy0">.</span> <span class="nu0">193</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="nu0">8</span> <span class="sy0">.</span> <span class="nu0">105</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="nu0">7</span> <span class="sy0">.</span> <span class="nu0">57</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="nu0">6</span> <span class="sy0">.</span> <span class="nu0">31</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="nu0">5</span> <span class="sy0">.</span> <span class="nu0">17</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="nu0">4</span> <span class="sy0">.</span> <span class="nu0">9</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="nu0">3</span> <span class="sy0">.</span> <span class="nu0">5</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="nu0">2</span> <span class="sy0">.</span> <span class="nu0">3</span><span class="br0">&#41;</span> <span class="br0">&#40;</span>-<span class="nu0">1</span> <span class="sy0">.</span> <span class="nu0">1</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="nu0">0</span> <span class="sy0">.</span> <span class="nu0">1</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="nu0">1</span> <span class="sy0">.</span> <span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div><b>А если переменных несколько</b><br />
<br />
На этом можно было бы остановиться. Но у нашего макро есть один серьезный недостаток: легко убедиться, что макро не будет работать с функцией нескольких переменных. Как решить эту проблему? В чем разница между одной или более переменными в списке параметров? Пусть вместо одного параметра будет список. Список вполне может быть ключом ассоциативного списка. Чуть подправим наше макро:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="469509717"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="469509717" style="height: 174px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">defmacro</span> memoize <span class="br0">&#40;</span>f<span class="br0">&#41;</span>
&nbsp; <span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>body <span class="br0">&#40;</span><span class="kw1">cdr</span> <span class="br0">&#40;</span>getd f<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>parm <span class="br0">&#40;</span><span class="kw1">cadr</span> <span class="br0">&#40;</span>getd f<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp;`<span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>asso <span class="kw1">nil</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span><span class="kw1">defun</span> <span class="sy0">,</span>f <span class="sy0">,</span>parm
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>tmp <span class="br0">&#40;</span><span class="kw1">assoc</span> <span class="br0">&#40;</span><span class="kw1">list</span> <span class="sy0">,</span>@parm<span class="br0">&#41;</span> asso<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">if</span> tmp <span class="br0">&#40;</span><span class="kw1">cdr</span> tmp<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>r <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="sy0">,</span>@body<span class="br0">&#41;</span> <span class="sy0">,</span>@parm<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span>push <span class="br0">&#40;</span><span class="kw1">cons</span> <span class="br0">&#40;</span><span class="kw1">list</span> <span class="sy0">,</span>@parm<span class="br0">&#41;</span> r<span class="br0">&#41;</span> asso<span class="br0">&#41;</span> r<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Что сделано? В двух местах (там, где идет обращение к ассоциативному списку) фактические параметры “заключены в скобки”. Конструкция (list ,@parm) может показаться странной: сначала мы (с помощью @) удаляем скобки, а затем тут же добавляем… Не проще ли просто написать ,parm? Не проще! Если бы мы попробовали это сделать, то у нас получилось бы (для мемоизируемой функции двух переменных x и y):<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="667013360"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="667013360" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>tmp <span class="br0">&#40;</span><span class="kw1">assoc</span> <span class="br0">&#40;</span>x y<span class="br0">&#41;</span> asso<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> …</pre></td></tr></table></div></td></tr></tbody></table></div>При вызове мемоизированной функции с параметрами, к примеру, x=5, y=6 этот фрагмент породит ошибку “отсутствие функции 5”.<br />
<br />
Проверим работоспособность макро на достаточно “дикой” функции:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="590479054"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="590479054" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">defun</span> g <span class="br0">&#40;</span>x y<span class="br0">&#41;</span>
&nbsp; <span class="br0">&#40;</span><span class="kw1">cond</span> <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw1">or</span> <span class="br0">&#40;</span><span class="sy0">&lt;=</span> x <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="sy0">&lt;=</span> y <span class="nu0">0</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="nu0">1</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>t <span class="br0">&#40;</span>+ <span class="br0">&#40;</span>g <span class="br0">&#40;</span>- x <span class="nu0">1</span><span class="br0">&#41;</span> y<span class="br0">&#41;</span> <span class="br0">&#40;</span>g x <span class="br0">&#40;</span>- y <span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#40;</span>g <span class="br0">&#40;</span>- x <span class="nu0">2</span><span class="br0">&#41;</span> <span class="br0">&#40;</span>- y <span class="nu0">2</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>По той же причине, что и наша первая fib, эта функция будет вычисляться очень долго. Но код работоспособен:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="38449140"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="38449140" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span>g <span class="nu0">6</span> <span class="nu0">7</span><span class="br0">&#41;</span>
<span class="sy0">==&gt;</span> <span class="nu0">5139</span></pre></td></tr></table></div></td></tr></tbody></table></div>Мемоизируем функцию g и повторяем вычисления:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="800319523"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="800319523" style="height: 110px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span>memoize g<span class="br0">&#41;</span>
<span class="sy0">==&gt;</span> G
&nbsp;
<span class="br0">&#40;</span>g <span class="nu0">6</span> <span class="nu0">7</span><span class="br0">&#41;</span>
<span class="sy0">==&gt;</span> <span class="nu0">5139</span></pre></td></tr></table></div></td></tr></tbody></table></div>На моем компьютере мемоизированная функция для аргументов 6 и 7 вычисляется за время, сопоставимое, со временем работы исходного варианта функции. Понятно, что после первого вычисления, последующие будут “выполняться” мгновенно, но все же обидно – прироста производительности почти нет…<br />
<br />
Причина – в ассоциативном списке. Поиск в ассоциативном списке выполняется за время O(n). Пришло время отказаться от ассоциативного списка и использовать вместо него хэш-таблицу. Поиск в хэш-таблице осуществляется быстрее, чем в ассоциативном списке. Посмотрим, даст ли замена ассоциативного списка на хэш-таблицу прирост производительности.<br />
<br />
<b>Хэш вместо ассоциативного списка<br />
</b><br />
<br />
В HomeLisp имеется возможность работы с хэш-таблицами (основанная на известном майкрософтовском dictionary). Для использования  хэш-таблицы, ее нужно предварительно создать (вызвав hashCreate). Затем можно заносить и извлекать данные, а также проверять наличие данных с заданным ключом. Подробнее - <a rel="nofollow noopener noreferrer" href="http://homelisp.ru/help/hash_funct.html" target="_blank" title="http://homelisp.ru/help/hash_funct.html"><b>здесь</b></a><br />
<br />
Функции hashCreate нужно дать на вход “чистый” атом. После успешного завершения список свойств этого атома модифицируется и атом станет “идентификатором” хэш-таблицы. Идентификаторы хэш-таблиц глобальны. Для нас это очень важно – если при мемоизации функции будет создаваться новая хэш-таблица, нужно обеспечить уникальность ее идентификатора. Проще всего сделать это можно с помощью стандартной функции gensym (создающей при каждом вызове уникальный атом).<br />
<br />
Переработанное макро может иметь вид:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="501345108"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="501345108" style="height: 206px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">defmacro</span> memoize <span class="br0">&#40;</span>f<span class="br0">&#41;</span>
&nbsp; <span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>h &nbsp; &nbsp;<span class="br0">&#40;</span><span class="kw1">gensym</span> '<span class="kw1">hash</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>body <span class="br0">&#40;</span><span class="kw1">cdr</span> <span class="br0">&#40;</span>getd f<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>parm <span class="br0">&#40;</span><span class="kw1">cadr</span> <span class="br0">&#40;</span>getd f<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp;`<span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="sy0">!</span><span class="kw1">hash</span> <span class="br0">&#40;</span><span class="kw1">quote</span> <span class="sy0">,</span>h<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>hashCreate <span class="br0">&#40;</span><span class="kw1">quote</span> <span class="sy0">,</span>h<span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">defun</span> <span class="sy0">,</span>f <span class="sy0">,</span>parm
&nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span><span class="kw1">if</span> <span class="br0">&#40;</span>hashKeyExist <span class="br0">&#40;</span><span class="kw1">quote</span> <span class="sy0">,</span>h<span class="br0">&#41;</span> <span class="br0">&#40;</span>output <span class="br0">&#40;</span><span class="kw1">list</span> <span class="sy0">,</span>@parm<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">car</span> <span class="br0">&#40;</span>hashGet <span class="br0">&#40;</span><span class="kw1">quote</span> <span class="sy0">,</span>h<span class="br0">&#41;</span> <span class="br0">&#40;</span>output <span class="br0">&#40;</span><span class="kw1">list</span> <span class="sy0">,</span>@parm<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>r <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="sy0">,</span>@body<span class="br0">&#41;</span> <span class="sy0">,</span>@parm<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>hashPut <span class="br0">&#40;</span><span class="kw1">quote</span> <span class="sy0">,</span>h<span class="br0">&#41;</span> <span class="br0">&#40;</span>output <span class="br0">&#40;</span><span class="kw1">list</span> <span class="sy0">,</span>@parm<span class="br0">&#41;</span><span class="br0">&#41;</span> r<span class="br0">&#41;</span> r<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Новое макро в целом повторяет старое. Только обращения к ассоциативному списку замены обращением к хэш-таблице. Переменная h на первом этапе раскрытия макро получит уникальное значение (что-то вроде hash3). Мы запоминаем это значение (оно может пригодиться), а дальше выполняем те же построения, что и для версии с ассоциативным списком. В качестве ключа мы используем список параметров, преобразованный в строку (это делает функция output). Все остальное – то же самое, что и в версии с ассоциативным списком.<br />
<br />
Проверяем работоспособность и убеждаемся, что скорость работы мемоизированной функции выше в несколько раз (на моей машине – в 3-4 раза).<br />
<br />
Мы можем поинтересоваться контекстом нашей функции. Но результатов вычислений мы уже не увидим – они скрыты в хэш-таблице. Единственное, что можно увидеть – это идентификатор этой таблицы:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="905009840"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="905009840" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span>context 'g<span class="br0">&#41;</span>
<span class="sy0">==&gt;</span> <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="sy0">!</span><span class="kw1">HASH</span> HASH5<span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>А теперь можно и “полюбоваться” на результаты предыдущих вычислений (с помощью встроенной функции hashMap):<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="347458701"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="347458701" style="height: 158px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span>hashMap 'hash5 <span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="br0">&#40;</span>k v<span class="br0">&#41;</span> <span class="br0">&#40;</span>printline <span class="br0">&#40;</span><span class="kw1">list</span> k v<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span>
&nbsp;
<span class="br0">&#40;</span><span class="st0">&quot;(0 7)&quot;</span> <span class="nu0">1</span><span class="br0">&#41;</span>
<span class="br0">&#40;</span><span class="st0">&quot;(0 6)&quot;</span> <span class="nu0">1</span><span class="br0">&#41;</span>
… … …
<span class="br0">&#40;</span><span class="st0">&quot;(6 5)&quot;</span> <span class="nu0">1241</span><span class="br0">&#41;</span>
<span class="br0">&#40;</span><span class="st0">&quot;(6 6)&quot;</span> <span class="nu0">2643</span><span class="br0">&#41;</span>
<span class="br0">&#40;</span><span class="st0">&quot;(6 7)&quot;</span> <span class="nu0">5139</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Комментарии здесь, я полагаю, излишни.<br />
<br />
<b>Последний &quot;бантик&quot;<br />
</b><br />
Нам осталось совсем немного – хотелось бы иметь возможность восстановить исходную функцию. Сейчас мы напишем макро unmemoize, которое восстановит исходный вид мемоизированной функции.<br />
<br />
Для этого следует в контексте хранить какой-либо ключ, который будет признаком того, что замыкание есть результат мемоизирования. Это сделать совсем легко:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="903024763"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="903024763" style="height: 238px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">defmacro</span> memoize <span class="br0">&#40;</span>f<span class="br0">&#41;</span>
&nbsp; <span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>h &nbsp; &nbsp;<span class="br0">&#40;</span><span class="kw1">gensym</span> '<span class="kw1">hash</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>body <span class="br0">&#40;</span><span class="kw1">cdr</span> <span class="br0">&#40;</span>getd f<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>parm <span class="br0">&#40;</span><span class="kw1">cadr</span> <span class="br0">&#40;</span>getd f<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp;`<span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="sy0">!</span>memoize <span class="br0">&#40;</span><span class="kw1">quote</span> <span class="sy0">,</span>f<span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>body <span class="br0">&#40;</span><span class="kw1">quote</span> <span class="sy0">,</span>body<span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="sy0">!</span><span class="kw1">hash</span> <span class="br0">&#40;</span><span class="kw1">quote</span> <span class="sy0">,</span>h<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>hashCreate <span class="br0">&#40;</span><span class="kw1">quote</span> <span class="sy0">,</span>h<span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">defun</span> <span class="sy0">,</span>f <span class="sy0">,</span>parm
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">if</span> <span class="br0">&#40;</span>hashKeyExist <span class="br0">&#40;</span><span class="kw1">quote</span> <span class="sy0">,</span>h<span class="br0">&#41;</span> <span class="br0">&#40;</span>output <span class="br0">&#40;</span><span class="kw1">list</span> <span class="sy0">,</span>@parm<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">car</span> <span class="br0">&#40;</span>hashGet <span class="br0">&#40;</span><span class="kw1">quote</span> <span class="sy0">,</span>h<span class="br0">&#41;</span> <span class="br0">&#40;</span>output <span class="br0">&#40;</span><span class="kw1">list</span> <span class="sy0">,</span>@parm<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>r <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="sy0">,</span>@body<span class="br0">&#41;</span> <span class="sy0">,</span>@parm<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>hashPut <span class="br0">&#40;</span><span class="kw1">quote</span> <span class="sy0">,</span>h<span class="br0">&#41;</span> <span class="br0">&#40;</span>output <span class="br0">&#40;</span><span class="kw1">list</span> <span class="sy0">,</span>@parm<span class="br0">&#41;</span><span class="br0">&#41;</span> r<span class="br0">&#41;</span> r<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Кроме ключа мы сохранили и исходное тело функции. Сейчас это нам понадобится. Пишем макро unmemoize:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="679184127"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="679184127" style="height: 126px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">defmacro</span> unmemoize <span class="br0">&#40;</span>f<span class="br0">&#41;</span>
&nbsp; <span class="br0">&#40;</span><span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">null</span> <span class="br0">&#40;</span><span class="kw1">assoc</span> '<span class="sy0">!</span>memoize <span class="br0">&#40;</span>context f<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#40;</span>raiseerror <span class="st0">&quot;Функция не была мемоизирована!&quot;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">let</span>* <span class="br0">&#40;</span><span class="br0">&#40;</span>context <span class="br0">&#40;</span>context f<span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span>body &nbsp; &nbsp;<span class="br0">&#40;</span><span class="kw1">cadr</span> <span class="br0">&#40;</span><span class="kw1">assoc</span> 'body context<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span>hashDestroy <span class="br0">&#40;</span><span class="kw1">cadr</span> <span class="br0">&#40;</span><span class="kw1">assoc</span> '<span class="sy0">!</span><span class="kw1">hash</span> context<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;`<span class="br0">&#40;</span><span class="kw1">defun</span> <span class="sy0">,</span>f <span class="sy0">,</span>@body<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Разберем этот код. На первом этапе раскрытия макро происходит обращение к контексту f. Если в контексте найден ключ !memoize (а контекст замыкания есть не что иное, как ассоциативный список), то мы на правильном пути. Если же ключ не найден (или контекст вообще пуст), то возбуждаем состояние ошибки.<br />
<br />
В противном случае достаем исходное тело функции и готовим форму, которая вычислится на втором этапе раскрытия (это самая последняя строка макро).<br />
<br />
Итак, мы реализовали вполне работоспособный вариант мемоизации, причем весьма простыми средствами.<br />
<br />
Спасибо, что дочитали до конца!<br />
<br />
Недавно мне попалась интересная <a rel="nofollow noopener noreferrer" href="https://skillbox.ru/media/code/idealnyy-yazyk-programmirovaniya/" target="_blank" title="https://skillbox.ru/media/code/idealnyy-yazyk-programmirovaniya/"><b>статья</b></a>. Автор размышляет на тему “Почему невозможно создать идеальный язык программирования”. Приводит множество резонных соображений. Но в конце проговаривается о том, что идеальный язык давно создан и, как вы думаете, он называется? :)<br />
<br />
<a rel="nofollow noopener noreferrer" href="https://habr.com/ru/post/576278/" target="_blank" title="https://habr.com/ru/post/576278/"><b>ссылка на статью</b></a></div>

]]></content:encoded>
			<dc:creator>Catstail</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/226808/7273.html</guid>
		</item>
		<item>
			<title>Задача о m максимумах</title>
			<link>https://www.cyberforum.ru/blogs/226808/6905.html</link>
			<pubDate>Wed, 06 Jan 2021 10:15:21 GMT</pubDate>
			<description><![CDATA[Выкладываю мою статью на хабре "Задача о m максимумах". Ее там заминусовали, но, возможно, она...]]></description>
			<content:encoded><![CDATA[<div>Выкладываю мою статью на хабре &quot;Задача о m максимумах&quot;. Ее там заминусовали, но, возможно, она кому-то покажется интересной...<br />
<br />
<br />
Старая-старая школьно-студенческая задача... Дан массив целых чисел. Требуется найти m его максимальных (или минимальных) элементов. Когда я задаю эту задачу учащимся, то почти в каждой группе находятся &quot;умельцы&quot;, решающие ее с помощью сортировки. В самом деле, это ведь так просто: сортируем массив по убыванию (вручную или подходящей библиотечной функцией) и просто берем m первых элементов. Конечно, иначе как алгоритмическим варварством такой подход не назовешь - найти m максимумов достаточно просто за один проход массива; сортировка существенно сложнее. И однажды я решил исследовать сей вопрос вычислительными экспериментами. Результаты этих экспериментов я и предлагаю вашему вниманию. Не исключено, что кому-то результаты помогут и в практической работе.<br />
<br />
Намекну - интуиция меня в целом не подвела.<br />
<br />
Без сортировки задача может быть решена, например, так. Создаем рабочий массив длины m и заполняем его начальными значениями. В общем случае можно в качестве такого значения выбрать минимальное значение int/integer для соответствующей среды программирования. А если известна нижняя граница значений исходного массива, то можно взять любое число, меньшее этой границы.<br />
<br />
Итак, рабочий массив заполнен одинаковыми значениями. Теперь берем элемент за элементом исходного массива и вставляем его в нужное место рабочего массива. При этом длину рабочего массива сохраняем равной m (после вставки последний элемент пропадает). Если очередной элемент меньше последнего значения рабочего массива, то он просто пропускается. Этот процесс имеет вычислительную сложность O(nm).  Тогда как сортировка в лучшем случае описывается асимптотикой O(n*og(n)). Асимптотики показывают, как ведет себя функция (в данном случае - время сортировки) при стремлении параметров к бесконечности. Можно сказать, что время описанного алгоритма при стремлении n к бесконечности задается формулой t1=k1*O(n), а время сортировки t2=k2*O(n*log(n)). Здесь k1 и k2 - некие константы, зависящие от процессора, языка программирования, операционной системы и других факторов. <br />
<br />
Я построил три системы тестов (для Питона, Java и VBA). Все тесты устроены по сути одинаково: строились массивы возрастающих размеров, заполнялись случайными числами задаваемого диапазона, сортировались с фиксацией времени и прогонялись через описанный выше алгоритм тоже с фиксацией времени. Каждый тест повторялся 10 раз и время усреднялось. В Питоне и Java использовалась встроенная сортировка, в VBA - реализация QuickSort.<br />
<br />
<b>Питон</b> Ниже показан код питоновских тестов.<br />
<br />
<div class="codeblock"><table class="python"><thead><tr><td colspan="2" id="159441262"  class="head">Python</td></tr></thead><tbody><tr class="li1"><td><div id="159441262" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
</pre></td><td class="de1"><pre class="de1"><span class="kw1">import</span> <span class="kw3">time</span>
<span class="kw1">from</span> <span class="kw3">random</span> <span class="kw1">import</span> randint
&nbsp; &nbsp; 
<span class="kw1">def</span> max_n_1<span class="br0">&#40;</span>arr<span class="sy0">,</span>n<span class="br0">&#41;</span>:
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">sorted</span><span class="br0">&#40;</span>arr<span class="sy0">,</span>reverse<span class="sy0">=</span><span class="kw2">True</span><span class="br0">&#41;</span><span class="br0">&#91;</span><span class="nu0">0</span>:n<span class="br0">&#93;</span>
&nbsp; &nbsp; 
<span class="kw1">def</span> max_n_2<span class="br0">&#40;</span>arr<span class="sy0">,</span>n<span class="br0">&#41;</span>:
&nbsp; &nbsp; res<span class="sy0">=</span><span class="br0">&#91;</span>-<span class="nu0">1</span> <span class="kw1">for</span> _ <span class="kw1">in</span> <span class="kw2">range</span><span class="br0">&#40;</span>n<span class="br0">&#41;</span><span class="br0">&#93;</span>
&nbsp; &nbsp; <span class="kw1">for</span> x <span class="kw1">in</span> arr:
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> x <span class="sy0">&gt;</span> res<span class="br0">&#91;</span>n-<span class="nu0">1</span><span class="br0">&#93;</span>:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i<span class="sy0">=</span>n-<span class="nu0">1</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; j<span class="sy0">=</span>i-<span class="nu0">1</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">while</span><span class="br0">&#40;</span>j<span class="sy0">&gt;=</span><span class="nu0">0</span> <span class="kw1">and</span> res<span class="br0">&#91;</span>j<span class="br0">&#93;</span><span class="sy0">&lt;</span>x<span class="br0">&#41;</span>:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; res<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">=</span>res<span class="br0">&#91;</span>j<span class="br0">&#93;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i<span class="sy0">=</span>i-<span class="nu0">1</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; j<span class="sy0">=</span>j-<span class="nu0">1</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; res<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">=</span>x
&nbsp; &nbsp; <span class="kw1">return</span> res &nbsp;
&nbsp; &nbsp; 
<span class="kw1">def</span> start<span class="br0">&#40;</span><span class="br0">&#41;</span>:
&nbsp;
&nbsp; &nbsp; k<span class="sy0">=</span><span class="nu0">10</span>
&nbsp; &nbsp; n<span class="sy0">=</span><span class="nu0">10000</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw1">print</span><span class="br0">&#40;</span><span class="st0">&quot;k=&quot;</span><span class="sy0">,</span>k<span class="br0">&#41;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw1">while</span><span class="br0">&#40;</span>n<span class="sy0">&lt;=</span><span class="nu0">500000</span><span class="br0">&#41;</span>:
&nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">print</span><span class="br0">&#40;</span><span class="st0">&quot;n=&quot;</span><span class="sy0">,</span>n<span class="sy0">,</span>end<span class="sy0">=</span><span class="st0">' '</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; t1<span class="sy0">=</span><span class="nu0">0.0</span>
&nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> i <span class="kw1">in</span> <span class="kw2">range</span><span class="br0">&#40;</span><span class="nu0">10</span><span class="br0">&#41;</span>:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; arr<span class="sy0">=</span><span class="br0">&#91;</span>randint<span class="br0">&#40;</span><span class="nu0">1</span><span class="sy0">,</span><span class="nu0">2000</span><span class="br0">&#41;</span> <span class="kw1">for</span> _ <span class="kw1">in</span> <span class="kw2">range</span><span class="br0">&#40;</span>n<span class="br0">&#41;</span><span class="br0">&#93;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; start_time <span class="sy0">=</span> <span class="kw3">time</span>.<span class="kw3">time</span><span class="br0">&#40;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; z1<span class="sy0">=</span>max_n_1<span class="br0">&#40;</span>arr<span class="sy0">,</span>k<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fin_time <span class="sy0">=</span> <span class="kw3">time</span>.<span class="kw3">time</span><span class="br0">&#40;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t1<span class="sy0">=</span>t1+<span class="br0">&#40;</span>fin_time-start_time<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">print</span><span class="br0">&#40;</span>t1/<span class="nu0">10.0</span><span class="sy0">,</span>end<span class="sy0">=</span><span class="st0">' '</span><span class="br0">&#41;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; t2<span class="sy0">=</span><span class="nu0">0.0</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> i <span class="kw1">in</span> <span class="kw2">range</span><span class="br0">&#40;</span><span class="nu0">10</span><span class="br0">&#41;</span>: 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; arr<span class="sy0">=</span><span class="br0">&#91;</span>randint<span class="br0">&#40;</span><span class="nu0">1</span><span class="sy0">,</span><span class="nu0">2000</span><span class="br0">&#41;</span> <span class="kw1">for</span> _ <span class="kw1">in</span> <span class="kw2">range</span><span class="br0">&#40;</span>n<span class="br0">&#41;</span><span class="br0">&#93;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; start_time <span class="sy0">=</span> <span class="kw3">time</span>.<span class="kw3">time</span><span class="br0">&#40;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; z2<span class="sy0">=</span>max_n_2<span class="br0">&#40;</span>arr<span class="sy0">,</span>k<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fin_time <span class="sy0">=</span> <span class="kw3">time</span>.<span class="kw3">time</span><span class="br0">&#40;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t2<span class="sy0">=</span>t2+<span class="br0">&#40;</span>fin_time-start_time<span class="br0">&#41;</span>
&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">print</span><span class="br0">&#40;</span>t2/<span class="nu0">10.0</span><span class="br0">&#41;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; n<span class="sy0">=</span>n+<span class="nu0">10000</span>
&nbsp; &nbsp; 
start<span class="br0">&#40;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Размеры массива менялись от 10 до 500 тыс. элементов с шагом 10 тыс. Было выполнено два прогона: определение пяти и десяти максимумов. Результат для 10 максимумов показан на первой прилагаемой картинке.<br />
<br />
Время здесь приведено в миллисекундах. Что видим? Сортировка отстает (на краю интервала - вдвое). Для пяти максимумов картина аналогична. И надо заметить, что хотя  питоновская сортировка очень эффективна, простой алгоритм оказывается быстрее. Заметны резкие провалы в производительности (зубцы на графиках). Они, вероятно, объясняются влиянием внутренних процессов (типа сборки мусора). Это же замечание относится и к другим графикам.<br />
<br />
<br />
<b>Java</b> Код тестов выглядел так:<br />
<br />
<div class="codeblock"><table class="java5"><thead><tr><td colspan="2" id="674431026"  class="head">Java</td></tr></thead><tbody><tr class="li1"><td><div id="674431026" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
</pre></td><td class="de1"><pre class="de1"><span class="kw2">import</span> <span class="co2">java.util.*</span><span class="sy0">;</span>
&nbsp;
&nbsp;
<span class="kw2">class</span> Start
<span class="br0">&#123;</span>
&nbsp; &nbsp;<span class="kw2">public</span> <span class="kw2">static</span> <span class="kw3">void</span> main<span class="br0">&#40;</span><span class="kw21">String</span> <span class="br0">&#91;</span><span class="br0">&#93;</span> args<span class="br0">&#41;</span>
&nbsp; &nbsp;<span class="br0">&#123;</span> &nbsp; 
&nbsp; &nbsp;
&nbsp; &nbsp; <span class="kw46">Random</span> random = <span class="kw2">new</span> <span class="kw46">Random</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw46">Scanner</span> inp = <span class="kw2">new</span> <span class="kw46">Scanner</span><span class="br0">&#40;</span><span class="kw21">System</span>.<span class="me1">in</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
&nbsp; &nbsp; <span class="kw3">long</span> startTime,endTime,tot1,tot2<span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw3">int</span> i,a,b,n,m,x,ii,jj,u <span class="sy0">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; a=<span class="nu0">1</span><span class="sy0">;</span>
&nbsp; &nbsp; b=<span class="nu0">3000</span><span class="sy0">;</span>
&nbsp; &nbsp; m=<span class="nu0">10</span><span class="sy0">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw21">System</span>.<span class="me1">out</span>.<span class="me1">println</span><span class="br0">&#40;</span>a+<span class="st0">&quot; &quot;</span>+b+<span class="st0">&quot; &quot;</span>+m<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span>n=<span class="nu0">10000</span><span class="sy0">;</span> n<span class="sy0">&lt;</span>=<span class="nu0">500000</span><span class="sy0">;</span> n+=<span class="nu0">10000</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">int</span> arr<span class="br0">&#91;</span><span class="br0">&#93;</span> = <span class="kw2">new</span> <span class="kw3">int</span><span class="br0">&#91;</span>n<span class="br0">&#93;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">int</span> ma<span class="br0">&#91;</span><span class="br0">&#93;</span> &nbsp;= <span class="kw2">new</span> <span class="kw3">int</span><span class="br0">&#91;</span>m<span class="br0">&#93;</span><span class="sy0">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; tot1=<span class="nu0">0</span><span class="sy0">;</span>
&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span>u=<span class="nu0">0</span><span class="sy0">;</span> u<span class="sy0">&lt;</span><span class="nu0">10</span><span class="sy0">;</span> u++<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span> &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span>i=<span class="nu0">0</span><span class="sy0">;</span> i<span class="sy0">&lt;</span>n<span class="sy0">;</span> i++<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;arr<span class="br0">&#91;</span>i<span class="br0">&#93;</span>=a+random.<span class="me1">nextInt</span><span class="br0">&#40;</span>b-a+<span class="nu0">1</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; startTime = <span class="kw21">System</span>.<span class="me1">currentTimeMillis</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw46">Arrays</span>.<span class="me1">sort</span><span class="br0">&#40;</span>arr<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;endTime = <span class="kw21">System</span>.<span class="me1">currentTimeMillis</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tot1=tot1+<span class="br0">&#40;</span>endTime-startTime<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; tot2=<span class="nu0">0</span><span class="sy0">;</span>
&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span>u=<span class="nu0">0</span><span class="sy0">;</span> u<span class="sy0">&lt;</span><span class="nu0">10</span><span class="sy0">;</span> u++<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span> &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span>i=<span class="nu0">0</span><span class="sy0">;</span> i<span class="sy0">&lt;</span>n<span class="sy0">;</span> i++<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; arr<span class="br0">&#91;</span>i<span class="br0">&#93;</span>=a+random.<span class="me1">nextInt</span><span class="br0">&#40;</span>b-a+<span class="nu0">1</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; startTime = <span class="kw21">System</span>.<span class="me1">currentTimeMillis</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span>i=<span class="nu0">0</span><span class="sy0">;</span> i<span class="sy0">&lt;</span>m<span class="sy0">;</span> i++<span class="br0">&#41;</span> ma<span class="br0">&#91;</span>i<span class="br0">&#93;</span>=-<span class="nu0">999999</span><span class="sy0">;</span>
&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span>i=<span class="nu0">0</span><span class="sy0">;</span> i<span class="sy0">&lt;</span>n<span class="sy0">;</span> i++<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; x=arr<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">;</span> &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>x <span class="sy0">&gt;</span>= ma<span class="br0">&#91;</span>m-<span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ii=m-<span class="nu0">1</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; jj=ii-<span class="nu0">1</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">while</span><span class="br0">&#40;</span>jj<span class="sy0">&gt;</span>=<span class="nu0">0</span> <span class="sy0">&amp;&amp;</span> ma<span class="br0">&#91;</span>jj<span class="br0">&#93;</span><span class="sy0">&lt;</span>x<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ma<span class="br0">&#91;</span>ii<span class="br0">&#93;</span>=ma<span class="br0">&#91;</span>jj<span class="br0">&#93;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ii--<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; jj--<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span> &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ma<span class="br0">&#91;</span>ii<span class="br0">&#93;</span>=x<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; endTime = <span class="kw21">System</span>.<span class="me1">currentTimeMillis</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tot2=tot2+<span class="br0">&#40;</span>endTime-startTime<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp;
&nbsp; &nbsp; &nbsp; <span class="kw21">System</span>.<span class="me1">out</span>.<span class="me1">println</span><span class="br0">&#40;</span>n+<span class="st0">&quot; &quot;</span>+tot1+<span class="st0">&quot; &quot;</span>+tot2<span class="br0">&#41;</span><span class="sy0">;</span> &nbsp;
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; <span class="br0">&#125;</span> 
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Здесь размер массива тоже менялся от 10 тыс. до 500 тыс. элементов. Время - в миллисекундах. Результат оказался весьма похожим на питоновский (только сортировка Javа, увы, медленнее; Правда JDK в моих тестах - 8-й версии, а Питон - 3.7).  <br />
<br />
<b>VBA</b><br />
<br />
В этом языке нет универсальной встроенной сортировки (можно, правда, сортировать ячейки листа, но в этом случае будут велики накладные расходы, связанные с загрузкой и выгрузкой данных). Поэтому пришлось реализовать QuickSort вручную. Все это выглядит так:<br />
<br />
<div class="codeblock"><table class="vb"><thead><tr><td colspan="2" id="318765063"  class="head">Visual Basic</td></tr></thead><tbody><tr class="li1"><td><div id="318765063" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
</pre></td><td class="de1"><pre class="de1"><span class="kw2">Private</span> <span class="kw4">Declare</span> <span class="kw2">Function</span> GetTickCount Lib <span class="st0">&quot;kernel32&quot;</span> () <span class="kw4">As</span> <span class="kw1">Long</span>
&nbsp;
<span class="co1">'::: Быстрая сортировка</span>
&nbsp;
<span class="kw2">Sub</span> QSort(A() <span class="kw4">As</span> <span class="kw1">Long</span>, <span class="kw4">Optional</span> b <span class="kw4">As</span> <span class="kw1">Long</span> = 1, <span class="kw4">Optional</span> e <span class="kw4">As</span> <span class="kw1">Long</span> = 0)
&nbsp;
&nbsp; &nbsp; <span class="kw3">If</span> b &gt; e <span class="kw3">Then</span> <span class="kw2">Exit</span> <span class="kw2">Sub</span>
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; i&amp; = b
&nbsp; &nbsp; j&amp; = e
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; w&amp; = A((i&amp; + j&amp;) / 2)
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; <span class="kw3">Do</span> <span class="kw3">While</span> (<span class="kw5">True</span>)
&nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; <span class="kw3">Do</span> <span class="kw3">While</span> (A(i&amp;) &lt; w&amp;)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;i&amp; = i&amp; + 1
&nbsp; &nbsp; &nbsp; <span class="kw3">Loop</span>
&nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; <span class="kw3">Do</span> <span class="kw3">While</span> (A(j&amp;) &gt; w&amp;)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;j&amp; = j&amp; - 1
&nbsp; &nbsp; &nbsp; <span class="kw3">Loop</span>
&nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; <span class="kw3">If</span> i&amp; &lt;= j&amp; <span class="kw3">Then</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Tmp&amp; = A(i&amp;)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;A(i&amp;) = A(j&amp;)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;A(j&amp;) = Tmp&amp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;i&amp; = i&amp; + 1
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;j&amp; = j&amp; - 1
&nbsp; &nbsp; &nbsp; <span class="kw3">End</span> <span class="kw3">If</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; <span class="kw3">If</span> i&amp; &gt; j&amp; <span class="kw3">Then</span> <span class="kw2">Exit</span> <span class="kw3">Do</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw3">Loop</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw3">If</span> j&amp; &gt; b <span class="kw3">Then</span> QSort A, b, j&amp;
&nbsp; &nbsp; <span class="kw3">If</span> i&amp; &lt; e <span class="kw3">Then</span> QSort A, i&amp;, e
&nbsp;
<span class="kw3">End</span> <span class="kw2">Sub</span>
&nbsp;
<span class="co1">'::: Проверка</span>
&nbsp;
<span class="kw2">Function</span> check(X() <span class="kw4">As</span> <span class="kw1">Long</span>) <span class="kw4">As</span> <span class="kw1">Boolean</span>
&nbsp;
&nbsp; &nbsp; &nbsp;n&amp; = <span class="kw4">UBound</span>(X)
&nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp;<span class="kw3">For</span> i&amp; = 1 <span class="kw3">To</span> n&amp; - 1
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw3">If</span> X(i&amp; + 1) &lt; X(i&amp;) <span class="kw3">Then</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Debug.<span class="kw4">Print</span> <span class="st0">&quot;Err! i=&quot;</span> + CStr(i&amp;)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; check = <span class="kw5">False</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">Exit</span> <span class="kw2">Function</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw3">End</span> <span class="kw3">If</span>
&nbsp; &nbsp; &nbsp;<span class="kw3">Next</span> i&amp;
&nbsp;
&nbsp; &nbsp; &nbsp;check = <span class="kw5">True</span>
&nbsp; &nbsp; &nbsp;
<span class="kw3">End</span> <span class="kw2">Function</span>
&nbsp;
<span class="co1">'::: Вставка в упорядоченный массив</span>
&nbsp;
<span class="kw2">Sub</span> ins_in_arr(X <span class="kw4">As</span> <span class="kw1">Long</span>, A() <span class="kw4">As</span> <span class="kw1">Long</span>, n <span class="kw4">As</span> <span class="kw1">Integer</span>)
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw3">If</span> X &lt; A(n) <span class="kw3">Then</span> <span class="kw2">Exit</span> <span class="kw2">Sub</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw3">For</span> i% = 1 <span class="kw3">To</span> n
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">If</span> X &gt; A(i%) <span class="kw3">Then</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw3">For</span> j% = n <span class="kw3">To</span> i% + 1 <span class="kw3">Step</span> -1
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;A(j%) = A(j% - 1)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw3">Next</span> j%
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;A(i%) = X
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw2">Exit</span> <span class="kw2">Sub</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">End</span> <span class="kw3">If</span>
&nbsp; &nbsp; <span class="kw3">Next</span> i%
&nbsp; &nbsp; 
<span class="kw3">End</span> <span class="kw2">Sub</span>
&nbsp;
<span class="co1">'::: Собственно тест</span>
&nbsp;
<span class="kw2">Sub</span> test()
Const sz = 500
<span class="kw4">Dim</span> X() <span class="kw4">As</span> <span class="kw1">Long</span>
<span class="kw4">Dim</span> Ma(1 <span class="kw3">To</span> sz) <span class="kw4">As</span> <span class="kw1">Long</span>
&nbsp;
&nbsp; &nbsp; Randomize
&nbsp;
&nbsp; &nbsp; ooo&amp; = 1
&nbsp;
&nbsp; &nbsp; <span class="kw3">For</span> n&amp; = 10000 <span class="kw3">To</span> 500000 <span class="kw3">Step</span> 10000
&nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; t1# = 0
&nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">For</span> nc% = 1 <span class="kw3">To</span> 10
&nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">ReDim</span> X(1 <span class="kw3">To</span> n&amp;) <span class="kw4">As</span> <span class="kw1">Long</span>
&nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">For</span> i&amp; = 1 <span class="kw3">To</span> n&amp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; X(i&amp;) = Rnd() * 5000
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">Next</span> i&amp;
&nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; s1&amp; = GetTickCount
&nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">For</span> i&amp; = 1 <span class="kw3">To</span> sz
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Ma(i&amp;) = -2147483647
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">Next</span> i&amp;
&nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">For</span> i&amp; = 1 <span class="kw3">To</span> n&amp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ins_in_arr X(i&amp;), Ma, 10
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">Next</span> i&amp;
&nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; s2&amp; = GetTickCount
&nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t1# = t1# + s2&amp; - s1&amp;
&nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">Next</span> nc%
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; Cells(ooo&amp;, 1).Value = n&amp;
&nbsp; &nbsp; &nbsp; &nbsp; Cells(ooo&amp;, 2).Value = t1# / 10
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; t2# = 0
&nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">For</span> nc% = 1 <span class="kw3">To</span> 10
&nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">ReDim</span> X(1 <span class="kw3">To</span> n&amp;) <span class="kw4">As</span> <span class="kw1">Long</span>
&nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">For</span> i&amp; = 1 <span class="kw3">To</span> n&amp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; X(i&amp;) = Rnd() * 5000
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">Next</span> i&amp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; s1&amp; = GetTickCount
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; QSort X, 1, n&amp;
&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; s2&amp; = GetTickCount
&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">If</span> <span class="kw3">Not</span> check(X) <span class="kw3">Then</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;MsgBox <span class="st0">&quot;Ошибка при сортировке!&quot;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw2">Exit</span> <span class="kw2">Sub</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">End</span> <span class="kw3">If</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t2# = t2# + s2&amp; - s1&amp;
&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">Next</span> nc%
&nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; Cells(ooo&amp;, 3).Value = t2# / 10
&nbsp; &nbsp; &nbsp; &nbsp; ooo&amp; = ooo&amp; + 1
&nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw3">Next</span> n&amp;
&nbsp;
<span class="kw3">End</span> <span class="kw2">Sub</span></pre></td></tr></table></div></td></tr></tbody></table></div>На каждом витке цикла корректность сортировки проверяется. Время проверки, естественно, не включается в общий хронометраж. Набор исходных данных тот же - от 10 до 500 тыс. целых чисел. Получает, в общем, похожая картина.<br />
<br />
Представляет некоторый интерес изучить зависимость времени от количества искомых максимумов (при фиксированном размере массива). Здесь, очевидно, сортировка будет тем выгоднее, чем больше максимумов требуется найти. А вставка в упорядоченный массив будет тем медленнее, чем массив больше.<br />
<br />
Самым невыгодным случаем будет являться, как ни странно, входной массив, уже упорядоченный по возрастанию. В этом случае количество сравнений при вставке достигнет максимума и будет равно n*m. Массив, упорядоченный по убыванию, напротив, весьма выгоден. Число сравнений здесь будет ~ m+n.<br />
<br />
Описанный в самом начале статьи алгоритм, можно ускорить, если вместо простого упорядоченного массива использовать древовидную или пирамидальную структуру. Именно так и реализована в Питоне в модуле heapq функция nsmallest.<br />
<br />
Для небольших массивов (несколько тысяч элементов и менее) разница в подходах представляется несущественной. И если нужно быстро написать код, то сортировка - вполне приемлемое решение. Для больших массивов выгоднее от сортировки отказаться.<br />
<br />
Вот и все, что я хотел рассказать об этой задаче. Спасибо, что дочитали до конца. С наступившим 2021-м годом!<br />
<br />
<a rel="nofollow noopener noreferrer" href="https://habr.com/ru/post/535870/" target="_blank" title="https://habr.com/ru/post/535870/"><b>ссылка на статью</b></a></div>


<!-- attachments -->
	<div style="margin-top:10px">

		
			<fieldset class="fieldset">
				<legend>Миниатюры</legend>
				<div style="padding:3px">
				
	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=6683&amp;d=1609927950" target="attachment" rel="Lightbox" id="attachment6683"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=6683&amp;stc=1&amp;thumb=1&amp;d=1609927950" border="0" alt="Нажмите на изображение для увеличения
Название: 10-python.png
Просмотров: 2033
Размер:	11.7 Кб
ID:	6683" /></a>
	&nbsp;
	

	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=6684&amp;d=1609927950" target="attachment" rel="Lightbox" id="attachment6684"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=6684&amp;stc=1&amp;thumb=1&amp;d=1609927950" border="0" alt="Нажмите на изображение для увеличения
Название: 10-java.png
Просмотров: 2038
Размер:	12.3 Кб
ID:	6684" /></a>
	&nbsp;
	

	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=6685&amp;d=1609927950" target="attachment" rel="Lightbox" id="attachment6685"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=6685&amp;stc=1&amp;thumb=1&amp;d=1609927950" border="0" alt="Нажмите на изображение для увеличения
Название: 10-vba.png
Просмотров: 2075
Размер:	12.4 Кб
ID:	6685" /></a>
	&nbsp;
	
		<br /><br />
	

				</div>
			</fieldset>
		
		
		
		

	</div>
<!-- / attachments -->
]]></content:encoded>
			<dc:creator>Catstail</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/226808/6905.html</guid>
		</item>
		<item>
			<title>Цена естественности или как обогнать QuickSort</title>
			<link>https://www.cyberforum.ru/blogs/226808/6808.html</link>
			<pubDate>Tue, 03 Nov 2020 19:19:21 GMT</pubDate>
			<description>Сортировка — такая же «вечная» тема для алгоритмистов, как любовь — для поэтов. Казалось бы, новое...</description>
			<content:encoded><![CDATA[<div>Сортировка — такая же «вечная» тема для алгоритмистов, как любовь — для поэтов. Казалось бы, новое слово в этой области сказать трудно, а поди же ты — продолжают придумывать новые алгоритмы сортировок (TimSort...) Есть, однако, базовые факты, которые знает каждый приличный студент. Известно, к примеру, что универсальный алгоритм сортировки не может быть быстрее O(n*log(n)). Такой показатель производительности имеет знаменитая QuckSort (придуманная в 1960-м году Хоаром), а также сортировка слиянием (Фон Неймана) и пирамидальная сортировка. Что же касается элементарных алгоритмов («пузырек», «вставки», «выбор»), то их показатель существенно хуже — O(n^2). Но всегда ли QuickSort является «абсолютным чемпионом»?<br />
<br />
Ведь кроме показателя производительности есть и другие характеристики, зачастую — не менее важные. Один из них — естественность. Что это такое? Сортировка называется естественной, если она выполняется быстрее в том случае, когда массив уже почти отсортирован. А какой массив можно считать «почти отсортированным»? Вот два массива, состоящие из одних и тех элементов:<br />
<br />
{1,2,9,3,4,5,7,6,8,10} и {9,1,6,3,10,5,4,2,8,7}<br />
<br />
Даже на глаз видно, что первый массив более упорядочен (только 9 и 7 стоят «не на месте»). Тогда как во втором массиве числа перемешаны хаотически. Что же является мерой упорядоченности? Ответ известен — количество инверсий. Пара элементов A[i] и A[j] при j &gt; i составляют инверсию, если A[j] &lt; A[i]. (В этой заметке целью сортировки всегда является упорядочение по возрастанию).<br />
<br />
Теперь можно дать точное определение: сортировка называется естественной, если время ее работы снижается при снижении количества инверсий в исходном массиве. Естественность — достаточно «редкий фрукт» в мире сортировок — ни QuickSort ни сортировка Шелла не обладают этим свойством, увы. Но есть один алгоритм, который, можно сказать, является абсолютно естественным — это сортировка вставками. Хотя этот алгоритм известен каждому культурному человеку, позволю себе кратко повторить его суть.<br />
<br />
Сортируемый массив просматривается один раз от начала к концу. Как только обнаруживается, что i-й и (i-1)-элементы образуют инверсию, i-й элемент «закидывается» назад (что достигается сдвигом нужного отрезка начала массива вправо на одну позицию). Из этого описания понятно, что если в массиве мало инверсий, алгоритм «пролетит» по массиву очень быстро. Если инверсий нет совсем, то алгоритм завершится за время O(n). А вот QuickSort в этом случае будет долго и утомительно выбирать разделяющий элемент, делить уже упорядоченный массив на отрезки и т.п. Но при наличии большого количества инверсий ситуация, разумеется, будет обратной: производительность сортировки вставками упадет до O(n^2), а QuickSort будет чемпионом — O(n*log(n)).<br />
<br />
Сложившаяся ситуация порождает естественный с моей точки зрения вопрос: при каком количестве инверсий перевешивает естественность и сортировка вставками работает быстрее QuickSort?<br />
<br />
Для ответа на этот вопрос я провел серию вычислительных экспериментов. Суть их состояла в следующем. Брались массивы целых чисел размером от 3000 до 30000 элементов, в них вносилось некоторое количество инверсий, затем массивы сортировались вставками и быстрой сортировкой. Замерялось время сортировки (в системных тиках). Для усреднения каждая сортировка повторялась 10 раз. Результаты оказались следующими:<br />
<br />
<img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=6555&amp;st= c=1&amp;thumb=1&amp;d=1604431436" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /><br />
<br />
На картинке представлены зависимости времени сортировки от количества внесенных инверсий. Малиновая серия - это, естественно, QuickSort, а синяя - сортировка вставками. Для размера массива 30 тыс. элементов, до примерно 400 тыс. инверсий &quot;побеждает естественность&quot;. Для менее упорядоченных массивов уже выгоднее QuickSort.<br />
<br />
А на следующей картинке приведена эмпирическая зависимость критического количества инверсий от размера массива. <br />
<br />
<img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=6556&amp;st= c=1&amp;thumb=1&amp;d=1604431436" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /><br />
<br />
Легко видеть, что для массива размера n критическое количество инверсий составляет примерно 10*n. При большем количестве инверсий выгоден QuickSort. Следует отметить, что максимальное количество инверсий для массива длины n составляет n*(n-1)/2. Величина 10*n есть весьма незначительная их часть. Что и неудивительно.<br />
<br />
К сказанному осталось добавить, что результаты таких экспериментов зависят от многих факторов (языка программирования, типа сортируемых данных и т.п.) Мне, честно говоря, было лень исследовать эти вопросы более детально. Мои эксперименты проводились в Microsoft Excel в среде VBA:<br />
<br />
<div class="codeblock"><table class="vb"><thead><tr><td colspan="2" id="53189919"  class="head">Visual Basic</td></tr></thead><tbody><tr class="li1"><td><div id="53189919" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
</pre></td><td class="de1"><pre class="de1"><span class="kw2">Private</span> <span class="kw4">Declare</span> <span class="kw2">Function</span> GetTickCount Lib <span class="st0">&quot;kernel32&quot;</span> () <span class="kw4">As</span> <span class="kw1">Long</span>
&nbsp;
<span class="co1">'::: Сортировка вставками </span>
&nbsp;
<span class="kw2">Sub</span> JSort(A() <span class="kw4">As</span> <span class="kw1">Long</span>)
&nbsp; &nbsp; n&amp; = <span class="kw4">UBound</span>(A, 1)
&nbsp; &nbsp; <span class="kw3">For</span> i&amp; = 2 <span class="kw3">To</span> n
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">If</span> A(i&amp;) &lt; A(i&amp; - 1) <span class="kw3">Then</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;j&amp; = i&amp; - 1
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;x&amp; = A(i&amp;)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw3">Do</span> <span class="kw3">While</span> (A(j&amp;) &gt; x&amp;)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; A(j&amp; + 1) = A(j&amp;)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; j&amp; = j&amp; - 1
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">If</span> j&amp; = 0 <span class="kw3">Then</span> <span class="kw2">Exit</span> <span class="kw3">Do</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw3">Loop</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;A(j&amp; + 1) = x&amp;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">End</span> <span class="kw3">If</span>
&nbsp; &nbsp; <span class="kw3">Next</span> i&amp;
<span class="kw3">End</span> <span class="kw2">Sub</span>
&nbsp;
<span class="co1">'::: Быстрая сортировка</span>
&nbsp;
<span class="kw2">Sub</span> QSort(A() <span class="kw4">As</span> <span class="kw1">Long</span>, <span class="kw4">Optional</span> b <span class="kw4">As</span> <span class="kw1">Long</span> = 1, <span class="kw4">Optional</span> e <span class="kw4">As</span> <span class="kw1">Long</span> = 0)
&nbsp; &nbsp; <span class="kw3">If</span> (e - b) &lt;= 1 <span class="kw3">Then</span> <span class="kw2">Exit</span> <span class="kw2">Sub</span>
&nbsp; &nbsp; i&amp; = b
&nbsp; &nbsp; j&amp; = e
&nbsp; &nbsp; w&amp; = A((i&amp; + j&amp;) / 2)
&nbsp; &nbsp; <span class="kw3">Do</span> <span class="kw3">While</span> (i&amp; &lt; j&amp;)
&nbsp; &nbsp; &nbsp; <span class="kw3">Do</span> <span class="kw3">While</span> (A(i&amp;) &lt; w&amp;)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;i&amp; = i&amp; + 1
&nbsp; &nbsp; &nbsp; <span class="kw3">Loop</span>
&nbsp; &nbsp; &nbsp; <span class="kw3">Do</span> <span class="kw3">While</span> (A(j&amp;) &gt; w&amp;)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;j&amp; = j&amp; - 1
&nbsp; &nbsp; &nbsp; <span class="kw3">Loop</span>
&nbsp; &nbsp; &nbsp; <span class="kw3">If</span> i&amp; &lt; j&amp; <span class="kw3">Then</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tmp&amp; = A(i&amp;)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;A(i&amp;) = A(j&amp;)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;A(j&amp;) = tmp&amp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;i&amp; = i&amp; + 1
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;j&amp; = j&amp; - 1
&nbsp; &nbsp; &nbsp; <span class="kw3">End</span> <span class="kw3">If</span>
&nbsp; &nbsp; <span class="kw3">Loop</span>
&nbsp; &nbsp; <span class="kw3">If</span> j&amp; &gt; b <span class="kw3">Then</span> QSort A, b, j&amp;
&nbsp; &nbsp; <span class="kw3">If</span> i&amp; &lt; e <span class="kw3">Then</span> QSort A, i&amp;, e
<span class="kw3">End</span> <span class="kw2">Sub</span>
&nbsp;
<span class="co1">'::: Случайные перестановки элементов (внесение инверсий)</span>
&nbsp;
<span class="kw2">Sub</span> InsInv(A() <span class="kw4">As</span> <span class="kw1">Long</span>, k <span class="kw4">As</span> <span class="kw1">Long</span>)
&nbsp; &nbsp; n&amp; = <span class="kw4">UBound</span>(A, 1)
&nbsp; &nbsp; <span class="kw3">For</span> i&amp; = 1 <span class="kw3">To</span> k
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">Do</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;k1&amp; = n&amp; * Rnd
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;k2&amp; = n&amp; * Rnd
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw3">If</span> (k1&amp; &lt;&gt; k2&amp;) <span class="kw3">And</span> (k1&amp; &gt;= 1) <span class="kw3">And</span> (k2&amp; &gt;= 1) <span class="kw3">Then</span> <span class="kw2">Exit</span> <span class="kw3">Do</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">Loop</span>
&nbsp; &nbsp; &nbsp; &nbsp; tmp&amp; = A(k1&amp;)
&nbsp; &nbsp; &nbsp; &nbsp; A(k1&amp;) = A(k2&amp;)
&nbsp; &nbsp; &nbsp; &nbsp; A(k2&amp;) = tmp&amp;
&nbsp; &nbsp; <span class="kw3">Next</span> i&amp;
<span class="kw3">End</span> <span class="kw2">Sub</span>
&nbsp;
<span class="co1">'::: Подсчет числа инверсий в массиве</span>
&nbsp;
<span class="kw2">Function</span> NumInv(A() <span class="kw4">As</span> <span class="kw1">Long</span>) <span class="kw4">As</span> <span class="kw1">Long</span>
&nbsp; &nbsp; n&amp; = <span class="kw4">UBound</span>(A, 1)
&nbsp; &nbsp; <span class="kw3">For</span> i&amp; = 1 <span class="kw3">To</span> n&amp; - 1
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">For</span> j&amp; = i&amp; + 1 <span class="kw3">To</span> n&amp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">If</span> A(j&amp;) &lt; A(i&amp;) <span class="kw3">Then</span> NumInv = NumInv + 1
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">Next</span> j&amp;
&nbsp; &nbsp; <span class="kw3">Next</span> i&amp;
<span class="kw3">End</span> <span class="kw2">Function</span>
&nbsp;
<span class="co1">'::: Главный тест</span>
&nbsp;
<span class="kw2">Sub</span> Gtest_1()
<span class="kw4">Dim</span> Eta() <span class="kw4">As</span> <span class="kw1">Long</span>
<span class="kw4">Dim</span> Arr() <span class="kw4">As</span> <span class="kw1">Long</span>
&nbsp; &nbsp; Size&amp; = CLng(InputBox(<span class="st0">&quot;Sz=&quot;</span>))
&nbsp; &nbsp; <span class="kw4">ReDim</span> Eta(1 <span class="kw3">To</span> Size&amp;) <span class="kw4">As</span> <span class="kw1">Long</span>
&nbsp; &nbsp; <span class="kw4">ReDim</span> Arr(1 <span class="kw3">To</span> Size&amp;) <span class="kw4">As</span> <span class="kw1">Long</span>
&nbsp; &nbsp; Randomize
&nbsp; &nbsp; <span class="kw3">For</span> i&amp; = 1 <span class="kw3">To</span> Size&amp;
&nbsp; &nbsp; &nbsp; &nbsp; Eta(i&amp;) = i&amp;
&nbsp; &nbsp; <span class="kw3">Next</span> i&amp;
&nbsp; &nbsp; q# = Size&amp; * (Size&amp; - 1) / 2
&nbsp; &nbsp; <span class="kw3">For</span> iii% = 1 <span class="kw3">To</span> 10
&nbsp; &nbsp; &nbsp; &nbsp; InsInv Eta, CLng(iii%)
&nbsp; &nbsp; &nbsp; &nbsp; ni# = CDbl(NumInv(Eta))
&nbsp; &nbsp; &nbsp; &nbsp; Cells(iii%, 1).Value = ni# &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">DoEvents</span>
&nbsp; &nbsp; &nbsp; &nbsp; S# = 0
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">For</span> l% = 1 <span class="kw3">To</span> 10
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">For</span> i&amp; = 1 <span class="kw3">To</span> Size&amp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Arr(i&amp;) = Eta(i&amp;)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">Next</span> i&amp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TBeg&amp; = GetTickCount
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; JSort Arr
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TEnd&amp; = GetTickCount
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; S# = S# + TEnd&amp; - TBeg&amp;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">Next</span> l%
&nbsp; &nbsp; &nbsp; &nbsp; Cells(iii%, 2).Value = S#
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">DoEvents</span>
&nbsp; &nbsp; &nbsp; &nbsp; S# = 0
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">For</span> l% = 1 <span class="kw3">To</span> 10
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">For</span> i&amp; = 1 <span class="kw3">To</span> Size&amp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Arr(i&amp;) = Eta(i&amp;)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">Next</span> i&amp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TBeg&amp; = GetTickCount
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; QSort Arr, 1, Size&amp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TEnd&amp; = GetTickCount
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; S# = S# + TEnd&amp; - TBeg&amp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">If</span> <span class="kw3">Not</span> check(Arr) <span class="kw3">Then</span> <span class="kw2">Exit</span> <span class="kw2">Sub</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">Next</span> l%
&nbsp; &nbsp; &nbsp; &nbsp; Cells(iii%, 3).Value = S#
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">DoEvents</span>
&nbsp; &nbsp; <span class="kw3">Next</span> iii%
&nbsp; &nbsp; MsgBox <span class="st0">&quot;OK&quot;</span>
<span class="kw3">End</span> <span class="kw2">Sub</span></pre></td></tr></table></div></td></tr></tbody></table></div>Спасибо за внимание!<br />
<br />
<a rel="nofollow noopener noreferrer" href="https://habr.com/ru/post/526346/" target="_blank" title="https://habr.com/ru/post/526346/"><b>ссылка на хабре</b></a></div>


<!-- attachments -->
	<div style="margin-top:10px">

		
			<fieldset class="fieldset">
				<legend>Миниатюры</legend>
				<div style="padding:3px">
				
	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=6555&amp;d=1604431436" target="attachment" rel="Lightbox" id="attachment6555"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=6555&amp;stc=1&amp;thumb=1&amp;d=1604431436" border="0" alt="Нажмите на изображение для увеличения
Название: iq-01.png
Просмотров: 448
Размер:	7.7 Кб
ID:	6555" /></a>
	&nbsp;
	

	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=6556&amp;d=1604431436" target="attachment" rel="Lightbox" id="attachment6556"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=6556&amp;stc=1&amp;thumb=1&amp;d=1604431436" border="0" alt="Нажмите на изображение для увеличения
Название: iq-02.png
Просмотров: 313
Размер:	7.9 Кб
ID:	6556" /></a>
	&nbsp;
	

				</div>
			</fieldset>
		
		
		
		

	</div>
<!-- / attachments -->
]]></content:encoded>
			<dc:creator>Catstail</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/226808/6808.html</guid>
		</item>
		<item>
			<title>Частичное применение и «каррирование» функций в Лиспе</title>
			<link>https://www.cyberforum.ru/blogs/226808/6772.html</link>
			<pubDate>Fri, 16 Oct 2020 10:35:46 GMT</pubDate>
			<description>Одно из известных преимуществ Лиспа над другими языками программирования состоит в том, что в Лиспе...</description>
			<content:encoded><![CDATA[<div>Одно из известных преимуществ Лиспа над другими языками программирования состоит в том, что в Лиспе проще, чем где бы то ни было, реализуются различные новые механизмы, появляющиеся в современных языках программирования. Причин тому несколько: это и гомоиконность Лиспа (единая форма представления программ и данных) и уникальная по своим возможностям система макро. В общем, Лисп не зря называют &quot;программируемым языком программирования&quot;.<br />
<br />
В этой небольшой заметке мы рассмотрим, как можно реализовать в Лиспе такой, весьма популярный ныне программный механизм, как частичное применение функций. При этом я буду использовать свою реализацию <a rel="nofollow noopener noreferrer" href="http://homelisp.ru" target="_blank" title="http://homelisp.ru"><b><a rel="nofollow noopener noreferrer" href="http://homelisp.ru" target="_blank" title="http://homelisp.ru">http://homelisp.ru</a></b></a> (это чистый интерпретатор Лиспа с некоторыми дополнительными возможностями). <br />
<br />
Вероятно, использование частичного применения в Common Lisp будет не очень простым (в связи с тем, что для вызова вычисляемого функционального объекта нужно использовать funcall/apply); в Scheme дело должно обстоять проще. В ближайшее время я планирую опубликовать новую версию HomeLisp, в котором для вызова вычисляемого функционального объекта не требуется funcall/apply. В тех случаях, когда поведение кода отличается, я буду это подчёркивать.<br />
<br />
Частичное применение - это строгая математическая операция. Но мы рассмотрим ее &quot;на пальцах&quot;, без обращения к лямбда-исчислению и комбинаторной логике.<br />
<br />
Частичное применение функции f - это получение из функции f новой функции f', которая уже приняла заданные аргументы, и готова принять остальные. Для чего нужно частичное применение? Например, для того, чтобы из функции можно было вернуть функциональное значение.<br />
<br />
Рассмотрим частичное применение на простом примере. Пусть функция f задана формулой:<br />
<br />
f(x,y,z)=x+y**2+z**3<br />
<br />
тогда частичное применение этой функции с аргументами x=1 и y=2 должно породить функцию:<br />
<br />
f'(z) = 1+4+z**3 = 5+z**3<br />
<br />
В языке Хаскелл частичное применение ничего не стоит программисту:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="728661470"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="728661470" style="height: 190px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
</pre></td><td class="de1"><pre class="de1">Prelude<span class="sy0">&gt;</span> f x y z <span class="sy0">=</span> x<span class="sy0">+</span>y<span class="sy0">**</span><span class="nu0">2</span><span class="sy0">+</span>z<span class="sy0">**</span><span class="nu0">3</span> &nbsp;<span class="co1">-- задаем функцию</span>
f <span class="sy0">::</span> <span class="kw5">Floating</span> a <span class="sy0">=&gt;</span> a <span class="sy0">-&gt;</span> a <span class="sy0">-&gt;</span> a <span class="sy0">-&gt;</span> a
Prelude<span class="sy0">&gt;</span> f <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">3</span> <span class="co1">-- проверим...</span>
<span class="nu0">32.0</span> <span class="co1">-- верно!</span>
it <span class="sy0">::</span> <span class="kw5">Floating</span> a <span class="sy0">=&gt;</span> a
Prelude<span class="sy0">&gt;</span> f' <span class="sy0">=</span> f <span class="nu0">1</span> <span class="nu0">2</span> &nbsp;<span class="co1">-- частично применяем её при x=1 y=2 и сохраняем новую функцию f'</span>
f' <span class="sy0">::</span> <span class="kw5">Floating</span> a <span class="sy0">=&gt;</span> a <span class="sy0">-&gt;</span> a
Prelude<span class="sy0">&gt;</span> f' <span class="nu0">3</span> <span class="co1">-- функция f' принимает один аргумент</span>
<span class="nu0">32.0</span> <span class="co1">-- и даёт верный результат</span>
it <span class="sy0">::</span> <span class="kw5">Floating</span> a <span class="sy0">=&gt;</span> a</pre></td></tr></table></div></td></tr></tbody></table></div>Однако, в Лиспе такая попытка приведет к неудаче:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="522508067"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="522508067" style="height: 254px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">defun</span> f <span class="br0">&#40;</span>x y z<span class="br0">&#41;</span> <span class="br0">&#40;</span>+ x <span class="br0">&#40;</span>* y y<span class="br0">&#41;</span> <span class="br0">&#40;</span>* z z z<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="co1">;; Определяем функцию</span>
<span class="sy0">==&gt;</span> F
&nbsp;
<span class="br0">&#40;</span>f <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">3</span><span class="br0">&#41;</span> <span class="co1">;; Проверяем работоспособность</span>
<span class="sy0">==&gt;</span> <span class="nu0">32</span> <span class="co1">;; Верно</span>
&nbsp;
<span class="br0">&#40;</span>f <span class="nu0">1</span> <span class="nu0">2</span><span class="br0">&#41;</span> <span class="co1">;; Пробуем задать не все аргументы...</span>
&nbsp;
PairLis<span class="sy0">:</span> Слишком мало фактических параметров 
&nbsp;
Функция<span class="sy0">:</span> <span class="me1">F</span>
Формальные &nbsp;параметры<span class="sy0">:</span> <span class="br0">&#40;</span>X Y Z<span class="br0">&#41;</span>
Фактические параметры<span class="sy0">:</span> <span class="br0">&#40;</span><span class="nu0">1</span> <span class="nu0">2</span><span class="br0">&#41;</span>
<span class="sy0">==&gt;</span> ERRSTATE</pre></td></tr></table></div></td></tr></tbody></table></div>Конечно, в Лиспе существует механизм создания функций с любым числом аргументов (конструкция &amp;rest); можно создать функцию, которая будет принимать два или три (или десять) параметров:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="60540105"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="60540105" style="height: 174px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">defun</span> s <span class="br0">&#40;</span><span class="sy0">&amp;</span>rest x<span class="br0">&#41;</span> <span class="co1">;; неопределенное к-во параметров собирается в список x</span>
&nbsp; <span class="br0">&#40;</span><span class="kw1">apply</span> '+ x<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="co1">;; и этот список суммируется</span>
<span class="sy0">==&gt;</span> S
&nbsp;
<span class="br0">&#40;</span>s <span class="nu0">1</span> <span class="nu0">2</span><span class="br0">&#41;</span> <span class="co1">;; два параметра</span>
<span class="sy0">==&gt;</span> <span class="nu0">3</span>
&nbsp;
<span class="br0">&#40;</span>s <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">3</span><span class="br0">&#41;</span> <span class="co1">;; три параметра</span>
<span class="sy0">==&gt;</span> <span class="nu0">6</span></pre></td></tr></table></div></td></tr></tbody></table></div>Но важно понимать разницу: эта функция обрабатывает все параметры и возвращает результат вычисления, тогда как частичное применение дает в результате новую функцию, которая &quot;готова продолжить вычисления&quot;.<br />
<br />
Посмотрим, как можно реализовать на Лиспе механизм частичного применения функции. И поможет нам в этом... да-да, аппарат анонимных функций (lambda). Некоторые программисты думают, что анонимные функции нужны только для экономии имен (мол, их место во всяких stream-map-filter-reduce для того, чтобы выполнить короткое действие над элементом последовательности). На самом же деле анонимные функции способны на гораздо большее, в чем мы сейчас и убедимся.<br />
<br />
Начнем с того, что рассмотрим, как функция может вернуть другую функцию как результат. В Лиспе это очень просто:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="22266089"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="22266089" style="height: 126px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">defun</span> func-gen <span class="br0">&#40;</span>x<span class="br0">&#41;</span>
&nbsp; &nbsp;<span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="br0">&#40;</span>y<span class="br0">&#41;</span> <span class="br0">&#40;</span>+ x <span class="br0">&#40;</span>* y y<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
<span class="sy0">==&gt;</span> FUNC-GEN
&nbsp;
<span class="br0">&#40;</span>func-gen <span class="nu0">5</span><span class="br0">&#41;</span>
<span class="sy0">==&gt;</span> <span class="br0">&#40;</span>CLOSURE <span class="br0">&#40;</span>Y<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>+ X <span class="br0">&#40;</span>* Y Y<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>X <span class="nu0">5</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Как видим, функция возвращает замыкание, в котором значение свободной переменной x зафиксировано (равно 5). Результат функции можно вызвать как функцию. Для этого в Common Lisp и HomeLisp (с редакцией ядра &lt;= 13.53) придется использовать funcall:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="237699165"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="237699165" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">funcall</span> <span class="br0">&#40;</span>func-gen <span class="nu0">5</span><span class="br0">&#41;</span> <span class="nu0">7</span><span class="br0">&#41;</span>
<span class="sy0">==&gt;</span> <span class="nu0">54</span></pre></td></tr></table></div></td></tr></tbody></table></div>Теперь понятно, как можно действовать, если мы хотим взять функцию f от n аргументов и одно значение x, а в результате получить функцию от (n-1) аргумента. Обозначим список формальных параметров нашей функции через plist. Тогда все, что нужно сделать, это построить вот такое лямбда-выражение:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="977582816"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="977582816" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="br0">&#40;</span>хвост-<span class="kw1">plist</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">apply</span> f <span class="br0">&#40;</span><span class="kw1">cons</span> x хвост-<span class="kw1">plist</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Идея очень проста: мы строим лямбда-выражение, в теле которого просто вызываем исходную функцию на списке параметров, в котором голова заменена на значение х.<br />
<br />
Значит, для частичного применения функции нужно на базе этой функции построить лямбда-выражение, у которого аргументов будет на единицу меньше, а аргумент, заданный при частичном применении, будет &quot;учтен&quot; во внутреннем вызове нашей функции в теле лямбда-выражения. <br />
Как это реализовать? Несложно... В HomeLisp есть функция getd, которая обеспечивает доступ к определяющему выражению функции или макро:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="974029709"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="974029709" style="height: 126px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">defun</span> g <span class="br0">&#40;</span>x y z<span class="br0">&#41;</span> <span class="br0">&#40;</span>+ x <span class="br0">&#40;</span>* x y<span class="br0">&#41;</span> <span class="br0">&#40;</span>* x y z<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp;
<span class="sy0">==&gt;</span> G
<span class="br0">&#40;</span>getd 'g<span class="br0">&#41;</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="br0">&#40;</span>EXPR <span class="br0">&#40;</span>X Y Z<span class="br0">&#41;</span> <span class="br0">&#40;</span>+ X <span class="br0">&#40;</span>* X Y<span class="br0">&#41;</span> <span class="br0">&#40;</span>* X Y Z<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Как видим, getd возвращает определяющее выражение функции, в котором &quot;вместо&quot; лямбда находится специальный атом EXPR. Мы можем взять список параметров нашей функции (второй элемент результата) и построить лямбда-выражение, параметрами которого будет хвост исходного списка параметров, а в теле лямбда-выражения мы вызовем исходную функцию с полным списком параметров.<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="441567011"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="441567011" style="height: 110px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">defun</span> part-<span class="kw1">apply</span> <span class="br0">&#40;</span>f a<span class="br0">&#41;</span>
&nbsp; <span class="br0">&#40;</span><span class="kw1">let</span>* <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw1">plist</span> <span class="br0">&#40;</span><span class="kw1">cadr</span> <span class="br0">&#40;</span>getd f<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="co1">;; исходный список параметров</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span>rlist <span class="br0">&#40;</span><span class="kw1">cdr</span> <span class="kw1">plist</span><span class="br0">&#41;</span><span class="br0">&#41;</span> &nbsp; &nbsp; <span class="co1">;; список параметров без первого </span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span>clist <span class="br0">&#40;</span><span class="kw1">cons</span> a rlist<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="co1">;; список для вызова с заданным a</span>
&nbsp; &nbsp; &nbsp; &nbsp; `<span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="sy0">,</span>rlist <span class="br0">&#40;</span><span class="kw1">apply</span> <span class="br0">&#40;</span><span class="kw1">quote</span> <span class="sy0">,</span>f<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">list</span> <span class="sy0">,</span>@clist<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Из приведенного кода легко понять, что plist - это исходный список функции f, которую мы хотим применить частично. rlist - исходный список без первого элемента, а clist - полный список параметров, в котором первый элемент заменен на значение x. Конкретно, для функции g, приведенной выше plist = (x y z), rlist=(y z), а clist=(a y z). Проверим теперь, как работает частичное применение:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="277465865"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="277465865" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span>part-<span class="kw1">apply</span> 'g <span class="nu0">111</span><span class="br0">&#41;</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="br0">&#40;</span><span class="kw1">LAMBDA</span> <span class="br0">&#40;</span>Y Z<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">APPLY</span> <span class="br0">&#40;</span><span class="kw1">QUOTE</span> G<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">LIST</span> <span class="nu0">111</span> Y Z<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Можно убедиться, что это именно то, что и планировалось: part-apply вернула новую функцию, с числом аргументов, на единицу меньшим. Если эту новую функцию вызвать с параметрами y и z, то результат будет в точности такой же, как и вызов исходной функции g с тремя аргументами: 111 y и z:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="4150984"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="4150984" style="height: 206px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span>g <span class="nu0">111</span> <span class="nu0">1</span> <span class="nu0">2</span><span class="br0">&#41;</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="nu0">444</span> <span class="co1">;; исходный результат</span>
&nbsp;
<span class="br0">&#40;</span><span class="kw1">funcall</span> <span class="br0">&#40;</span>part-<span class="kw1">apply</span> 'g <span class="nu0">111</span><span class="br0">&#41;</span> <span class="nu0">1</span> <span class="nu0">2</span><span class="br0">&#41;</span> <span class="co1">;; вызов &quot;по-коммон-лисповски&quot;</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="nu0">444</span> 
&nbsp;
<span class="br0">&#40;</span><span class="br0">&#40;</span>part-<span class="kw1">apply</span> 'g <span class="nu0">111</span><span class="br0">&#41;</span> <span class="nu0">1</span> <span class="nu0">2</span><span class="br0">&#41;</span> <span class="co1">;; вызов &quot;по-схемному&quot;</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="nu0">444</span></pre></td></tr></table></div></td></tr></tbody></table></div>Ниже я (для краткости) не буду указывать funcall. В следующем ядре HomeLisp будет изменена схема вычисления функций - станет доступным &quot;схемный&quot; синтаксис.<br />
<br />
Пойдем дальше. Теперь возникнет естественное желание повторно применить результат повторного применения. Это оказывается уже совсем простым делом - ведь результат частичного применения - это лямбда-выражение, а оно устроено почти идентично с результатом, который возвращает getd. Список параметров лямбда-выражения - это второй элемент списка. Все эти соображения позволяют построить окончательное решение поставленной задачи:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="106378884"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="106378884" style="height: 222px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">defun</span> part-<span class="kw1">apply</span> <span class="br0">&#40;</span>f a<span class="br0">&#41;</span>
&nbsp; <span class="br0">&#40;</span><span class="kw1">cond</span> <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw1">and</span> <span class="br0">&#40;</span><span class="kw1">atom</span> f<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">member</span> 'expr <span class="br0">&#40;</span>proplist f<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="co1">;; *** функция ***</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span><span class="kw1">let</span>* <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw1">plist</span> <span class="br0">&#40;</span><span class="kw1">cadr</span> <span class="br0">&#40;</span>getd f<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="co1">;; исходный список параметров</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>rlist <span class="br0">&#40;</span><span class="kw1">cdr</span> <span class="kw1">plist</span><span class="br0">&#41;</span><span class="br0">&#41;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">;; список параметров без первого </span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>clist <span class="br0">&#40;</span><span class="kw1">cons</span> a rlist<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> &nbsp; &nbsp;<span class="co1">;; список для вызова с заданным a </span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;`<span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="sy0">,</span>rlist <span class="br0">&#40;</span><span class="kw1">apply</span> <span class="br0">&#40;</span><span class="kw1">quote</span> <span class="sy0">,</span>f<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">list</span> <span class="sy0">,</span>@clist<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw1">eq</span> '<span class="kw1">lambda</span> <span class="br0">&#40;</span><span class="kw1">car</span> f<span class="br0">&#41;</span><span class="br0">&#41;</span> &nbsp; <span class="co1">;; *** лямбда-выражение ***</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span><span class="kw1">let</span>* <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="kw1">plist</span> <span class="br0">&#40;</span><span class="kw1">cadr</span> f<span class="br0">&#41;</span><span class="br0">&#41;</span> &nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">;; исходный список параметров</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>rlist <span class="br0">&#40;</span><span class="kw1">cdr</span> <span class="kw1">plist</span><span class="br0">&#41;</span><span class="br0">&#41;</span> &nbsp; &nbsp; &nbsp; <span class="co1">;; список параметров без первого </span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>clist <span class="br0">&#40;</span><span class="kw1">cons</span> x rlist<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="co1">;; список для вызова с заданным x</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;`<span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="sy0">,</span>rlist <span class="br0">&#40;</span><span class="kw1">apply</span> <span class="br0">&#40;</span><span class="kw1">quote</span> <span class="sy0">,</span>f<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">list</span> <span class="sy0">,</span>@clist<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>t <span class="br0">&#40;</span>raiseerror <span class="st0">&quot;part-apply: неверен функциональный аргумент&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Здесь добавлен анализ первого параметра: если это атом, то он должен &quot;представлять&quot; функцию (типа EXPR); если первый параметр не является ни &quot;правильным&quot; атомом, ни лямбда-выражением, то возбуждается состояние ошибки. Код, разумеется, можно было бы еще подсократить, две почти идентичные ветви оставлены для наглядности. Посмотрим теперь, на что способна эта функция:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="724076245"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="724076245" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span>part-<span class="kw1">apply</span> <span class="br0">&#40;</span>part-<span class="kw1">apply</span> 'g <span class="nu0">1</span><span class="br0">&#41;</span> <span class="nu0">2</span><span class="br0">&#41;</span> <span class="co1">;; двукратное применение возвращает функцию одного аргумента</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="br0">&#40;</span><span class="kw1">LAMBDA</span> <span class="br0">&#40;</span>Z<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">APPLY</span> <span class="br0">&#40;</span><span class="kw1">QUOTE</span> <span class="br0">&#40;</span><span class="kw1">LAMBDA</span> <span class="br0">&#40;</span>Y Z<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">APPLY</span> <span class="br0">&#40;</span><span class="kw1">QUOTE</span> G<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">LIST</span> <span class="nu0">1</span> Y Z<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">LIST</span> <span class="nu0">2</span> Z<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp;
<span class="br0">&#40;</span><span class="br0">&#40;</span>part-<span class="kw1">apply</span> <span class="br0">&#40;</span>part-<span class="kw1">apply</span> 'g <span class="nu0">1</span><span class="br0">&#41;</span> <span class="nu0">2</span><span class="br0">&#41;</span> <span class="nu0">3</span><span class="br0">&#41;</span> <span class="co1">;; ее можно вызвать и получить верный результат</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="nu0">9</span>
&nbsp;
<span class="br0">&#40;</span>part-<span class="kw1">apply</span> <span class="br0">&#40;</span>part-<span class="kw1">apply</span> <span class="br0">&#40;</span>part-<span class="kw1">apply</span> 'g <span class="nu0">111</span><span class="br0">&#41;</span> <span class="nu0">1</span><span class="br0">&#41;</span> <span class="nu0">2</span><span class="br0">&#41;</span> <span class="co1">;; трехкратное применение возвратит безаргументную функцию</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="br0">&#40;</span><span class="kw1">LAMBDA</span> <span class="kw1">NIL</span> <span class="br0">&#40;</span><span class="kw1">APPLY</span> <span class="br0">&#40;</span><span class="kw1">QUOTE</span> <span class="br0">&#40;</span><span class="kw1">LAMBDA</span> <span class="br0">&#40;</span>Z<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">APPLY</span> <span class="br0">&#40;</span><span class="kw1">QUOTE</span> <span class="br0">&#40;</span><span class="kw1">LAMBDA</span> <span class="br0">&#40;</span>Y Z<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">APPLY</span> <span class="br0">&#40;</span><span class="kw1">QUOTE</span> G<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">LIST</span> <span class="nu0">111</span> Y Z<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">LIST</span> <span class="nu0">1</span> Z<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">LIST</span> <span class="nu0">2</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp;
<span class="br0">&#40;</span><span class="br0">&#40;</span>part-<span class="kw1">apply</span> <span class="br0">&#40;</span>part-<span class="kw1">apply</span> <span class="br0">&#40;</span>part-<span class="kw1">apply</span> 'g <span class="nu0">111</span><span class="br0">&#41;</span> <span class="nu0">1</span><span class="br0">&#41;</span> <span class="nu0">2</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="co1">;; ее тоже можно вызвать...</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="nu0">444</span>
&nbsp;
<span class="br0">&#40;</span><span class="kw1">setq</span> u <span class="br0">&#40;</span>part-<span class="kw1">apply</span> 'g <span class="nu0">111</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="co1">;; результат частичного применения можно присвоить переменной</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="br0">&#40;</span><span class="kw1">LAMBDA</span> <span class="br0">&#40;</span>Y Z<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">APPLY</span> <span class="br0">&#40;</span><span class="kw1">QUOTE</span> G<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">LIST</span> <span class="nu0">111</span> Y Z<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
<span class="co1">;; Создана глобальная переменная U</span>
&nbsp;
<span class="br0">&#40;</span>part-<span class="kw1">apply</span> u <span class="nu0">1</span><span class="br0">&#41;</span> <span class="co1">;; частичное применение можно продолжить</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="br0">&#40;</span><span class="kw1">LAMBDA</span> <span class="br0">&#40;</span>Z<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">APPLY</span> <span class="br0">&#40;</span><span class="kw1">QUOTE</span> <span class="br0">&#40;</span><span class="kw1">LAMBDA</span> <span class="br0">&#40;</span>Y Z<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">APPLY</span> <span class="br0">&#40;</span><span class="kw1">QUOTE</span> G<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">LIST</span> <span class="nu0">111</span> Y Z<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">LIST</span> <span class="nu0">1</span> Z<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp;
<span class="br0">&#40;</span><span class="br0">&#40;</span>part-<span class="kw1">apply</span> u <span class="nu0">1</span><span class="br0">&#41;</span> <span class="nu0">2</span><span class="br0">&#41;</span> <span class="co1">;; а можно вызвать</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="nu0">444</span></pre></td></tr></table></div></td></tr></tbody></table></div>Мы научились частично применять функцию, &quot;отщепляя&quot; при каждом применении по одному аргументу. А теперь хотелось бы иметь средство, позволяющее вызвать функцию с любым количеством аргументов. Таким свойством обладают в языке Хаскелл каррированные функции. А мы распространим наш механизм &quot;одократного применения&quot; на любое количество заданных аргументов.<br />
<br />
Пусть дана функция g нескольких аргументов. Мы построим ее &quot;каррированный&quot; вариант под другим именем !g. Суть построения будет такой: функция !g будет принимать неопределенное число аргументов. После вызова она должна проверить количество переданных аргументов. Если это количество равно количеству аргументов исходной функции g, то следует из передать на вход g. Если количество аргументов больше, чем способна принять g, то следует возбудить состояние ошибки. А вот если количество аргументов меньше, чем у функции g, то... да-да - нужно выполнить последовательное частичное применение. Результат этого применения вернуть. <br />
<br />
Такое преобразование функции, строго говоря, не есть каррирование (с точки зрения математики). Назовем эту процедуру псевдокаррированием.<br />
<br />
В данном случае удобно использовать макро. Код с комментариями приведен ниже:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="323327292"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="323327292" style="height: 286px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span><span class="kw1">defmacro</span> pcurry <span class="br0">&#40;</span>f<span class="br0">&#41;</span>
&nbsp; &nbsp;<span class="br0">&#40;</span><span class="kw1">let</span>* <span class="br0">&#40;</span><span class="br0">&#40;</span>parmlist <span class="br0">&#40;</span><span class="kw1">cadr</span> <span class="br0">&#40;</span>getd f<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="co1">;; список параметров f</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span>body &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span><span class="kw1">cddr</span> <span class="br0">&#40;</span>getd f<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="co1">;; тело функции f</span>
&nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span>lp &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span><span class="kw1">length</span> parmlist<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="co1">;; длина списка параметров f</span>
&nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span>cf &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span>implode <span class="br0">&#40;</span><span class="kw1">cons</span> '<span class="sy0">!</span> <span class="br0">&#40;</span>explode f<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="co1">;; новое имя для результата каррирования</span>
`<span class="br0">&#40;</span><span class="kw1">defun</span> <span class="sy0">,</span>cf <span class="br0">&#40;</span><span class="sy0">&amp;</span>rest x<span class="br0">&#41;</span>
&nbsp; &nbsp;<span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>lx <span class="br0">&#40;</span><span class="kw1">length</span> x<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="co1">;; длина актуального списка параметров</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">cond</span> &nbsp;<span class="br0">&#40;</span><span class="br0">&#40;</span><span class="sy0">=</span> lx <span class="sy0">,</span>lp<span class="br0">&#41;</span> <span class="co1">;; полное применение</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>e `<span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="sy0">,</span>parmlist <span class="sy0">,</span>@body<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">apply</span> e x<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="sy0">&gt;</span> lx <span class="sy0">,</span>lp<span class="br0">&#41;</span> <span class="co1">;; параметров слишком много</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>raiseerror <span class="st0">&quot;curry: Слишком много фактических параметров&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>t <span class="br0">&#40;</span><span class="kw1">let</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>tmp <span class="kw1">nil</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="co1">;; здесь будет результат</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>iter <span class="br0">&#40;</span>for a in x<span class="br0">&#41;</span> <span class="co1">;; частично применяем заданные параметры</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span><span class="kw1">setq</span> tmp <span class="br0">&#40;</span><span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">null</span> tmp<span class="br0">&#41;</span> <span class="br0">&#40;</span>part-<span class="kw1">apply</span> <span class="br0">&#40;</span><span class="kw1">quote</span> <span class="sy0">,</span>f<span class="br0">&#41;</span> a<span class="br0">&#41;</span> <span class="br0">&#40;</span>part-<span class="kw1">apply</span> tmp a<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tmp<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Здесь следует прокомментировать построение нового имени функции. Для этого используются функции HomeLisp explode, которая из атома строит список составляющих его символов, и implode, которая сжимает символы списка в один, порождая новый атом.<br />
<br />
Проверим теперь наш макро в &quot;деле&quot;:<br />
<br />
<div class="codeblock"><table class="lisp"><thead><tr><td colspan="2" id="417627630"  class="head">Lisp</td></tr></thead><tbody><tr class="li1"><td><div id="417627630" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#40;</span>pcurry g<span class="br0">&#41;</span> <span class="co1">;; &quot;каррируем&quot; g</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="sy0">!</span>G <span class="co1">;; &quot;каррированный&quot; вариант</span>
&nbsp;
<span class="br0">&#40;</span><span class="sy0">!</span>g <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">3</span><span class="br0">&#41;</span> <span class="co1">;; при обычном вызове</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="nu0">9</span> <span class="co1">;; ведет себя как g</span>
&nbsp;
<span class="br0">&#40;</span><span class="sy0">!</span>g <span class="nu0">1</span> <span class="nu0">2</span><span class="br0">&#41;</span> <span class="co1">;; если аргументов недостаточно - вернет функцию для обработки остальных</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="br0">&#40;</span><span class="kw1">LAMBDA</span> <span class="br0">&#40;</span>Z<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">APPLY</span> <span class="br0">&#40;</span><span class="kw1">QUOTE</span> <span class="br0">&#40;</span><span class="kw1">LAMBDA</span> <span class="br0">&#40;</span>Y Z<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">APPLY</span> <span class="br0">&#40;</span><span class="kw1">QUOTE</span> G<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">LIST</span> <span class="nu0">1</span> Y Z<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw1">LIST</span> <span class="nu0">2</span> Z<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp;
<span class="co1">;; Можно сразу и вычислить результат:</span>
&nbsp;
<span class="br0">&#40;</span><span class="br0">&#40;</span><span class="sy0">!</span>g <span class="nu0">1</span> <span class="nu0">2</span><span class="br0">&#41;</span> <span class="nu0">3</span><span class="br0">&#41;</span> <span class="co1">;; остался один аргумент</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="nu0">9</span>
&nbsp;
<span class="br0">&#40;</span><span class="br0">&#40;</span><span class="sy0">!</span>g <span class="nu0">1</span><span class="br0">&#41;</span> <span class="nu0">2</span> <span class="nu0">3</span><span class="br0">&#41;</span> <span class="co1">;; осталось два аргумента</span>
&nbsp;
<span class="sy0">==&gt;</span> <span class="nu0">9</span>
&nbsp;
<span class="br0">&#40;</span><span class="sy0">!</span>g <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">3</span> <span class="nu0">4</span><span class="br0">&#41;</span> <span class="co1">;; лишние аргументы вызовут ошибку</span>
&nbsp;
curry<span class="sy0">:</span> Слишком много фактических параметров
<span class="sy0">==&gt;</span> ERRSTATE</pre></td></tr></table></div></td></tr></tbody></table></div>&quot;Каррирование&quot; у нас выполнено без дополнительного контроля. И мы не реализовали &quot;каррирования&quot; лямбда-выражение. При желании все это можно сделать...<br />
<br />
Вот так можно без большого напряжения сил реализовать в Лиспе частичное применение функций. Лисп - замечательный язык!<br />
<br />
Спасибо за внимание.</div>

]]></content:encoded>
			<dc:creator>Catstail</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/226808/6772.html</guid>
		</item>
		<item>
			<title>Вычисление определителя на Хаскелл</title>
			<link>https://www.cyberforum.ru/blogs/226808/6721.html</link>
			<pubDate>Fri, 04 Sep 2020 16:30:29 GMT</pubDate>
			<description>Решил выложить код вычисления определителей. Код рабочий, хотя и не претендует на виртуозность....</description>
			<content:encoded><![CDATA[<div>Решил выложить код вычисления определителей. Код рабочий, хотя и не претендует на виртуозность. Просто было интересно решить эту задачу именно на Хаскелле. Рассмотрены два подхода к решению задачи: простая рекурсия и метод Гаусса.<br />
<br />
<b>Немного теории</b><br />
<br />
Как известно, определитель квадратной матрицы n*n - это  сумма n! слагаемых, каждое из которых есть произведение, содержащее ровно по одному элементу матрицы из каждого столбца и ровно по одному из каждой строки. Знак очередного произведения: <br />
<br />
<img src="https://www.cyberforum.ru/cgi-bin/latex.cgi?%7Ba%7D_%7B1%2Ci1%7D%2A%7Ba%7D_%7B2%2Ci2%7D%2A...%7Ba%7D_%7Bn%2Cin%7D" border="0" alt="https://www.cyberforum.ru/cgi-bin/latex.cgi?{a}_{1,i1}*{a}_{2,i2}*...{a}_{n,in}" /><br />
определяется чётностью подстановки:<br />
<img src="https://www.cyberforum.ru/cgi-bin/latex.cgi?%3Cbr%20%2F%3E%0D%0A%5Cbegin%7Bpmatrix%7D1%20%26amp%3B%202%20%26amp%3B%20...%20%26amp%3B%20n%20%5C%5C%20%7Bi%7D_%7B1%7D%20%26amp%3B%20%7Bi%7D_%7B2%7D%20%26amp%3B%20...%20%20%26amp%3B%20%7Bi%7D_%7Bn%7D%20%5Cend%7Bpmatrix%7D%3Cbr%20%2F%3E%0D%0A" border="0" alt="https://www.cyberforum.ru/cgi-bin/latex.cgi<br />
\begin{pmatrix}1 &amp; 2 &amp; ... &amp; n \\ {i}_{1} &amp; {i}_{2} &amp; ...  &amp; {i}_{n} \end{pmatrix}<br />
" /><br />
<br />
Прямой метод вычисления определителя состоит в разложении его по элементам строки или столбца в сумму произведений элементов какой-либо строки или столбца на их алгебраические дополнения. В свою очередь, алгебраическое дополнение элемента матрицы <img src="https://www.cyberforum.ru/cgi-bin/latex.cgi?%7Ba%7D_%7Bi%2Cj%7D" border="0" alt="https://www.cyberforum.ru/cgi-bin/latex.cgi?{a}_{i,j}" /> есть <img src="https://www.cyberforum.ru/cgi-bin/latex.cgi?%7B%28-1%29%7D%5E%7Bi%2Bj%7D%2A%7BM%7D_%7Bi%2Cj%7D" border="0" alt="https://www.cyberforum.ru/cgi-bin/latex.cgi?{(-1)}^{i+j}*{M}_{i,j}" /> при этом <img src="https://www.cyberforum.ru/cgi-bin/latex.cgi?%7BM%7D_%7Bi%2Cj%7D" border="0" alt="https://www.cyberforum.ru/cgi-bin/latex.cgi?{M}_{i,j}" /> - есть минор элемента (i,j), т.е. определитель, получающийся из исходного определителя вычеркиванием i-й строки и j-го столбца.<br />
<br />
Такой метод порождает рекурсивный процесс, позволяющий вычислить любой определитель. Но производительность этого алгоритма оставляет желать лучшего - O(n!). Поэтому применяется такое прямое вычисление разве что при символьных выкладках (и с определителями не слишком высокого порядка).<br />
<br />
Гораздо производительнее оказывается метод Гаусса. Его суть основывается на следующих положениях:<br />
<br />
1. Определитель верхней треугольной матрицы <img src="https://www.cyberforum.ru/cgi-bin/latex.cgi?%5Cbegin%7Bpmatrix%7D%7Ba%7D_%7B1%2C1%7D%20%26amp%3B%20%7Ba%7D_%7B1%2C2%7D%20%26amp%3B%20...%20%26amp%3B%20%7Ba%7D_%7B1%2Cn%7D%20%5C%5C%20%200%20%26amp%3B%20%7Ba%7D_%7B2%2C2%7D%20%26amp%3B%20...%20%26amp%3B%20%7Ba%7D_%7B2%2Cn%7D%20%5C%5C%20%200%20%26amp%3B%200%20%26amp%3B%20...%20%26amp%3B%20...%5C%5C%20%20%200%20%26amp%3B%200%20%26amp%3B%20...%20%26amp%3B%20%7Ba%7D_%7Bn%2Cn%7D%20%5C%5C%5Cend%7Bpmatrix%7D" border="0" alt="https://www.cyberforum.ru/cgi-bin/latex.cgi?\begin{pmatrix}{a}_{1,1} &amp; {a}_{1,2} &amp; ... &amp; {a}_{1,n} \\  0 &amp; {a}_{2,2} &amp; ... &amp; {a}_{2,n} \\  0 &amp; 0 &amp; ... &amp; ...\\   0 &amp; 0 &amp; ... &amp; {a}_{n,n} \\\end{pmatrix}" /> равен произведению ее диагональных элементов. Этот факт сразу же следует из разложения определителя по элементам первой строки или первого столбца.<br />
<br />
2. Если в матрице к элементам одной строки прибавить элементы другой строки, умноженные на одно и то же число, то значение определителя не изменится.<br />
<br />
3. Если в матрице поменять местами две строки (или два столбца), то значение определителя изменит знак на противоположный.<br />
<br />
Мы можем, подбирая коэффициенты, складывать первую строку матрицы со всеми остальными и получать в первом столбце нули во всех позициях, кроме первой. Для получения нуля во второй строке, нужно прибавить ко второй строке первую, умноженную на <img src="https://www.cyberforum.ru/cgi-bin/latex.cgi?-%7Ba%7D_%7B2%2C1%7D%2F%7Ba%7D_%7B1%2C1%7D" border="0" alt="https://www.cyberforum.ru/cgi-bin/latex.cgi?-{a}_{2,1}/{a}_{1,1}" /> Для получения нуля в третьей строке, нужно к третьей строке прибавить первую строку, умноженную на <img src="https://www.cyberforum.ru/cgi-bin/latex.cgi?-%7Ba%7D_%7B3%2C1%7D%2F%7Ba%7D_%7B1%2C1%7D" border="0" alt="https://www.cyberforum.ru/cgi-bin/latex.cgi?-{a}_{3,1}/{a}_{1,1}" /> и т.д. В конечном итоге, матрица приведется к виду, в котором все элементы <img src="https://www.cyberforum.ru/cgi-bin/latex.cgi?%7Ba%7D_%7Bn%2C1%7D" border="0" alt="https://www.cyberforum.ru/cgi-bin/latex.cgi?{a}_{n,1}" /> при n&gt;1 будут равны нулю. <br />
<br />
Если же в матрице элемент <img src="https://www.cyberforum.ru/cgi-bin/latex.cgi?%7Ba%7D_%7B1%2C1%7D" border="0" alt="https://www.cyberforum.ru/cgi-bin/latex.cgi?{a}_{1,1}" /> оказался равным нулю, то можно найти в первом столбце ненулевой элемент (предположим, он оказался на k-м месте) и обменять местами первую и k-ю строки. При этом преобразовании определитель просто поменяет знак, что можно учесть. Если же в первом столбце нет ненулевых элементов, то определитель  равен нулю.<br />
<br />
Далее, действуя аналогично, можно получить нули во втором столбце, затем в третьем и т.п. Важно, что при сложении строк полученные ранее нули не изменятся. Если для какой-либо строки не удастся найти ненулевой элемент для знаменателя, то определитель равен нулю и процесс можно остановить. Нормальное завершение процесса Гаусса порождает матрицу, у которой все элементы, расположенные ниже главной диагонали, равны нулю. Как говорилось выше, определитель такой матрицы равен произведению диагональных элементов.<br />
<br />
<b>Перейдем к программированию.<br />
</b> <br />
Мы работаем с данными с плавающей точкой. Матрицы представляем списками строк.  Для начала определим два типа:<br />
<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="949464622"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="949464622" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1"><span class="kw1">type</span> Row &nbsp; &nbsp;<span class="sy0">=</span> <span class="br0">&#91;</span><span class="kw4">Double</span><span class="br0">&#93;</span>
<span class="kw1">type</span> Matrix <span class="sy0">=</span> <span class="br0">&#91;</span>Row<span class="br0">&#93;</span></pre></td></tr></table></div></td></tr></tbody></table></div><b>Простая рекурсия</b><br />
<br />
Ничтоже сумняшеся, мы будем раскладывать определитель по элементам первой (т.е. нулевой) строки. Нам понадобится программа построения минора, получающегося вычеркиванием первой строки и k-го столбца. <br />
<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="343751203"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="343751203" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1"><span class="co1">-- Удаление k-го элемента изо всех строк матрицы</span>
deln <span class="sy0">::</span> Matrix <span class="sy0">-&gt;</span> <span class="kw4">Int</span> <span class="sy0">-&gt;</span> Matrix
deln matrix k <span class="sy0">=</span> <span class="kw3">map</span> <span class="br0">&#40;</span><span class="sy0">\</span> r <span class="sy0">-&gt;</span> <span class="br0">&#40;</span><span class="kw3">take</span> <span class="br0">&#40;</span>k<span class="br0">&#41;</span> r<span class="br0">&#41;</span><span class="sy0">++</span><span class="br0">&#40;</span><span class="kw3">drop</span> <span class="br0">&#40;</span>k<span class="sy0">+</span><span class="nu0">1</span><span class="br0">&#41;</span> r<span class="br0">&#41;</span><span class="br0">&#41;</span> matrix</pre></td></tr></table></div></td></tr></tbody></table></div><br />
А вот и минор:<br />
<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="276516443"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="276516443" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1"><span class="co1">-- Минор k-го элемента нулевой строки</span>
minor <span class="sy0">::</span> Matrix <span class="sy0">-&gt;</span> <span class="kw4">Int</span> <span class="sy0">-&gt;</span> <span class="kw4">Double</span>
minor matrix k <span class="sy0">=</span> det <span class="sy0">$</span> deln <span class="br0">&#40;</span><span class="kw3">drop</span> <span class="nu0">1</span> matrix<span class="br0">&#41;</span> k</pre></td></tr></table></div></td></tr></tbody></table></div>Обратите внимание: минор - это определитель. Мы вызываем функцию det, которую еще не реализовали. Для реализации det, нам придется сформировать знакочередующуюся сумму произведений очередного элемента первой строки на определитель очередного минора. Чтобы избежать громоздких выражений, создадим для формирования знака суммы отдельную функцию:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="369734355"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="369734355" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1">sgn <span class="sy0">::</span> <span class="kw4">Int</span> <span class="sy0">-&gt;</span> <span class="kw4">Double</span>
sgn n <span class="sy0">=</span> <span class="kw1">if</span> n `<span class="kw3">rem</span>` <span class="nu0">2</span> <span class="sy0">==</span> <span class="nu0">0</span> <span class="kw1">then</span> <span class="nu0">1.0</span> <span class="kw1">else</span> <span class="br0">&#40;</span><span class="sy0">-</span><span class="nu0">1.0</span><span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Теперь можно вычислить определитель:<br />
<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="417732778"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="417732778" style="height: 110px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
</pre></td><td class="de1"><pre class="de1"><span class="co1">-- Определитель квадратной матрицы</span>
det <span class="sy0">::</span> Matrix <span class="sy0">-&gt;</span> <span class="kw4">Double</span>
det <span class="br0">&#91;</span><span class="br0">&#91;</span>a,b<span class="br0">&#93;</span>,<span class="br0">&#91;</span>c,d<span class="br0">&#93;</span><span class="br0">&#93;</span> <span class="sy0">=</span> a<span class="sy0">*</span>d<span class="sy0">-</span>b<span class="sy0">*</span>c
det matrix <span class="sy0">=</span> <span class="kw3">sum</span> <span class="sy0">$</span> <span class="kw3">map</span> <span class="br0">&#40;</span><span class="sy0">\</span>c <span class="sy0">-&gt;</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>matrix <span class="sy0">!!</span> <span class="nu0">0</span><span class="br0">&#41;</span><span class="sy0">!!</span>c<span class="br0">&#41;</span><span class="sy0">*</span><span class="br0">&#40;</span>sgn c<span class="br0">&#41;</span><span class="sy0">*</span><span class="br0">&#40;</span>minor matrix c<span class="br0">&#41;</span><span class="br0">&#41;</span> &nbsp;<span class="br0">&#91;</span><span class="nu0">0</span>..n<span class="br0">&#93;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">where</span> n <span class="sy0">=</span> <span class="kw3">length</span> matrix <span class="sy0">-</span> <span class="nu0">1</span></pre></td></tr></table></div></td></tr></tbody></table></div>Код очень прост и не требует особых комментариев. Чтобы проверить работоспособность наших функций, напишем функцию main:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="580479842"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="580479842" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">main <span class="sy0">=</span> <span class="kw3">print</span> <span class="sy0">$</span> det <span class="br0">&#91;</span><span class="br0">&#91;</span><span class="nu0">1</span>,<span class="nu0">2</span>,<span class="nu0">3</span><span class="br0">&#93;</span>,<span class="br0">&#91;</span><span class="nu0">4</span>,<span class="nu0">5</span>,<span class="nu0">6</span><span class="br0">&#93;</span>,<span class="br0">&#91;</span><span class="nu0">7</span>,<span class="nu0">8</span>,<span class="br0">&#40;</span><span class="sy0">-</span><span class="nu0">9</span><span class="br0">&#41;</span><span class="br0">&#93;</span><span class="br0">&#93;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Значение этого определителя равно 54, в чем можно убедиться.<br />
<br />
<b>Метод Гаусса<br />
</b><br />
Нам понадобится несколько служебных функций (которые можно будет использовать и в других местах). Первая из них - взаимный обмен двух строк в матрице:<br />
<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="429103745"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="429103745" style="height: 142px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
</pre></td><td class="de1"><pre class="de1"><span class="co1">-- Обмен двух строк матрицы</span>
swap <span class="sy0">::</span> Matrix <span class="sy0">-&gt;</span> <span class="kw4">Int</span> <span class="sy0">-&gt;</span> <span class="kw4">Int</span> <span class="sy0">-&gt;</span> Matrix
swap matrix n1 n2 <span class="sy0">=</span> <span class="kw3">map</span> row <span class="br0">&#91;</span><span class="nu0">0</span>..n<span class="br0">&#93;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">where</span> n<span class="sy0">=</span><span class="kw3">length</span> matrix <span class="sy0">-</span> <span class="nu0">1</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; row k <span class="sy0">|</span> k<span class="sy0">==</span>n1 <span class="sy0">=</span> matrix <span class="sy0">!!</span> n2
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">|</span> k<span class="sy0">==</span>n2 <span class="sy0">=</span> matrix <span class="sy0">!!</span> n1
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">|</span> <span class="kw3">otherwise</span> <span class="sy0">=</span> matrix <span class="sy0">!!</span> k</pre></td></tr></table></div></td></tr></tbody></table></div>Как можно понять по приведенному выше коду, функция проходит строку за строкой. При этом, если встретилась строка с номером n1, принудительно подставляется строка n2 (и наоборот). Остальные строки остаются на месте.<br />
<br />
Следующая функция вычисляет строку r1 сложенную со строкой r2, умноженной поэлементно на число f:<br />
<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="898808066"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="898808066" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1"><span class="co1">-- Вычислить строку r1+f*r2</span>
comb <span class="sy0">::</span> Row <span class="sy0">-&gt;</span> Row <span class="sy0">-&gt;</span> <span class="kw4">Double</span> <span class="sy0">-&gt;</span> Row
comb r1 r2 f <span class="sy0">=</span> <span class="kw3">zipWith</span> <span class="br0">&#40;</span><span class="sy0">\</span> x y <span class="sy0">-&gt;</span> x<span class="sy0">+</span>f<span class="sy0">*</span>y<span class="br0">&#41;</span> r1 r2</pre></td></tr></table></div></td></tr></tbody></table></div>Здесь все предельно прозрачно: действия выполняются над строками матрицы (т.е. над списками [Double]). А вот следующая функция выполняет это преобразование над матрицей (и, естественно, получает новую матрицу):<br />
<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="638020074"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="638020074" style="height: 126px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
</pre></td><td class="de1"><pre class="de1"><span class="co1">-- прибавить к строке r1 строку r2, умноженную на f</span>
trans <span class="sy0">::</span> Matrix <span class="sy0">-&gt;</span> <span class="kw4">Int</span> <span class="sy0">-&gt;</span> <span class="kw4">Int</span> <span class="sy0">-&gt;</span> <span class="kw4">Double</span> <span class="sy0">-&gt;</span> Matrix
trans matrix n1 n2 f <span class="sy0">=</span> <span class="kw3">map</span> row <span class="br0">&#91;</span><span class="nu0">0</span>..n<span class="br0">&#93;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">where</span> n<span class="sy0">=</span><span class="kw3">length</span> matrix <span class="sy0">-</span> <span class="nu0">1</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;row k <span class="sy0">|</span> k<span class="sy0">==</span>n1 <span class="sy0">=</span> comb <span class="br0">&#40;</span>matrix <span class="sy0">!!</span> n1<span class="br0">&#41;</span> <span class="br0">&#40;</span>matrix <span class="sy0">!!</span> n2<span class="br0">&#41;</span> f
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy0">|</span> <span class="kw3">otherwise</span> <span class="sy0">=</span> matrix <span class="sy0">!!</span> k</pre></td></tr></table></div></td></tr></tbody></table></div>Функция getNz ищет номер первого ненулевого элемента в списке. Она нужна в случае, когда очередной диагональный элемент оказался равным нулю.<br />
<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="15754345"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="15754345" style="height: 94px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
</pre></td><td class="de1"><pre class="de1"><span class="co1">-- Номер первого ненулевого в списке</span>
getNz <span class="sy0">::</span> Row <span class="sy0">-&gt;</span> <span class="kw4">Int</span>
getNz xs <span class="sy0">=</span> <span class="kw1">if</span> <span class="kw3">length</span> tmp <span class="sy0">==</span> <span class="nu0">0</span> <span class="kw1">then</span> <span class="br0">&#40;</span><span class="sy0">-</span><span class="nu0">1</span><span class="br0">&#41;</span> <span class="kw1">else</span> <span class="kw3">snd</span> <span class="sy0">$</span> <span class="kw3">head</span> tmp
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">where</span> tmp<span class="sy0">=</span><span class="kw3">dropWhile</span> <span class="br0">&#40;</span><span class="sy0">\</span> <span class="br0">&#40;</span>x,k<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> <span class="br0">&#40;</span><span class="kw3">abs</span> x<span class="br0">&#41;</span> <span class="sy0">&lt;=</span> 1.0e<span class="sy0">-</span>10<span class="br0">&#41;</span> <span class="sy0">$</span> <span class="kw3">zip</span> xs <span class="br0">&#91;</span><span class="nu0">0</span>..<span class="br0">&#93;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Если все элементы списка равны нулю, функция вернет -1.<br />
<br />
Функция search проверяет, подходит ли матрица для очередного преобразования (у нее должен быть ненулевым очередной диагональный элемент). Если это не так, матрица преобразовывается перестановкой строк.<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="50651129"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="50651129" style="height: 174px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
</pre></td><td class="de1"><pre class="de1"><span class="co1">-- Поиск ведущего элемента и перестановка строк при необходимости</span>
search <span class="sy0">::</span> Matrix <span class="sy0">-&gt;</span> <span class="kw4">Int</span> <span class="sy0">-&gt;</span> Matrix
search matrix k <span class="sy0">|</span> <span class="br0">&#40;</span><span class="kw3">abs</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>matrix <span class="sy0">!!</span> k<span class="br0">&#41;</span> <span class="sy0">!!</span> k<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy0">&gt;</span> 1.0e<span class="sy0">-</span>10 <span class="sy0">=</span> matrix
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">|</span> nz <span class="sy0">&lt;</span> <span class="nu0">0</span> <span class="sy0">=</span> matrix &nbsp;<span class="co1">-- матрица вырождена &nbsp; &nbsp;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">|</span> <span class="kw3">otherwise</span> <span class="sy0">=</span> swap matrix k p 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">where</span> n &nbsp; <span class="sy0">=</span> <span class="kw3">length</span> matrix
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;lst <span class="sy0">=</span> <span class="kw3">map</span> <span class="br0">&#40;</span><span class="sy0">\</span> r <span class="sy0">-&gt;</span> r <span class="sy0">!!</span> k<span class="br0">&#41;</span> <span class="sy0">$</span> <span class="kw3">drop</span> k matrix
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;nz &nbsp;<span class="sy0">=</span> getNz lst
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;p &nbsp; <span class="sy0">=</span> k <span class="sy0">+</span> nz</pre></td></tr></table></div></td></tr></tbody></table></div>Если ведущий (ненулевой) элемент найти невозможно (матрица вырождена), то функция вернет ее без изменений. Функция mkzero формирует нули в очередном столбце матрицы:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="471021851"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="471021851" style="height: 126px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
</pre></td><td class="de1"><pre class="de1"><span class="co1">-- получение нулей в нужном столбце</span>
mkzero <span class="sy0">::</span> Matrix <span class="sy0">-&gt;</span> <span class="kw4">Int</span> <span class="sy0">-&gt;</span> <span class="kw4">Int</span> <span class="sy0">-&gt;</span> Matrix
mkzero matrix k p <span class="sy0">|</span> p<span class="sy0">&gt;</span>n<span class="sy0">-</span><span class="nu0">1</span> <span class="sy0">=</span> matrix
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">|</span> <span class="kw3">otherwise</span> <span class="sy0">=</span> mkzero <span class="br0">&#40;</span>trans matrix p k <span class="br0">&#40;</span><span class="sy0">-</span>f<span class="br0">&#41;</span><span class="br0">&#41;</span> k <span class="br0">&#40;</span>p<span class="sy0">+</span><span class="nu0">1</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">where</span> n <span class="sy0">=</span> <span class="kw3">length</span> matrix
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; f <span class="sy0">=</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>matrix <span class="sy0">!!</span> p<span class="br0">&#41;</span> <span class="sy0">!!</span> k<span class="br0">&#41;</span><span class="sy0">/</span><span class="br0">&#40;</span><span class="br0">&#40;</span>matrix <span class="sy0">!!</span> k<span class="br0">&#41;</span> <span class="sy0">!!</span> k<span class="br0">&#41;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Функция triangle формирует верхнюю треугольную форму матрицы:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="493004492"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="493004492" style="height: 174px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
</pre></td><td class="de1"><pre class="de1"><span class="co1">-- Получение верхней треугольной формы матрицы</span>
triangle <span class="sy0">::</span> Matrix <span class="sy0">-&gt;</span> <span class="kw4">Int</span> <span class="sy0">-&gt;</span> Matrix
triangle matrix k <span class="sy0">|</span> k<span class="sy0">&gt;=</span>n <span class="sy0">=</span> matrix
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">|</span> <span class="br0">&#40;</span><span class="kw3">abs</span> v<span class="br0">&#41;</span> <span class="sy0">&lt;=</span> 1.0e<span class="sy0">-</span>10 <span class="sy0">=</span> <span class="br0">&#91;</span><span class="br0">&#91;</span><span class="nu0">0.0</span><span class="br0">&#93;</span><span class="br0">&#93;</span> <span class="co1">-- матрица вырождена</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">|</span> <span class="kw3">otherwise</span> <span class="sy0">=</span> triangle <span class="br0">&#40;</span>mkzero tmp k k1<span class="br0">&#41;</span> k1 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">where</span> n &nbsp; <span class="sy0">=</span> <span class="kw3">length</span> matrix
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tmp <span class="sy0">=</span> search matrix k
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; v &nbsp; <span class="sy0">=</span> <span class="br0">&#40;</span>tmp <span class="sy0">!!</span> k<span class="br0">&#41;</span> <span class="sy0">!!</span> k <span class="co1">-- диагональный элемент</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; k1 &nbsp;<span class="sy0">=</span> k<span class="sy0">+</span><span class="nu0">1</span></pre></td></tr></table></div></td></tr></tbody></table></div>Если на очередном этапе не удалось найти ведущий элемент, функция возвращает нулевую матрицу 1-го порядка. Теперь можно составить парадную функцию приведения матрицы к верхней треугольной форме:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="675612959"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="675612959" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1"><span class="co1">-- Парадная функция</span>
gauss <span class="sy0">::</span> Matrix <span class="sy0">-&gt;</span> Matrix
gauss matrix <span class="sy0">=</span> triangle matrix <span class="nu0">0</span></pre></td></tr></table></div></td></tr></tbody></table></div>Для вычисления определителя нам нужно перемножить диагональные элементы. Для этого составим отдельную функцию:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="853068377"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="853068377" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1"><span class="co1">-- Произведение диагональных элементов</span>
proddiag <span class="sy0">::</span> Matrix <span class="sy0">-&gt;</span> <span class="kw4">Double</span>
proddiag matrix <span class="sy0">=</span> <span class="kw3">product</span> <span class="sy0">$</span> <span class="kw3">map</span> <span class="br0">&#40;</span><span class="sy0">\</span> <span class="br0">&#40;</span>r,k<span class="br0">&#41;</span> <span class="sy0">-&gt;</span> r <span class="sy0">!!</span>k<span class="br0">&#41;</span> <span class="sy0">$</span> <span class="kw3">zip</span> matrix <span class="br0">&#91;</span><span class="nu0">0</span>,<span class="nu0">1</span>..<span class="br0">&#93;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Ну, и &quot;бантик&quot; - собственно вычисление определителя:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="987158749"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="987158749" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1"><span class="co1">-- Вычисление определителя</span>
det <span class="sy0">::</span> Matrix <span class="sy0">-&gt;</span> <span class="kw4">Double</span>
det matrix <span class="sy0">=</span> proddiag <span class="sy0">$</span> triangle matrix <span class="nu0">0</span></pre></td></tr></table></div></td></tr></tbody></table></div>Проверим, как работает эта функция:<br />
<br />
<div class="codeblock"><table class="haskell"><thead><tr><td colspan="2" id="734350300"  class="head">Haskell</td></tr></thead><tbody><tr class="li1"><td><div id="734350300" style="height: 110px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
</pre></td><td class="de1"><pre class="de1">main <span class="sy0">=</span> <span class="kw3">print</span> <span class="sy0">$</span> det &nbsp;<span class="br0">&#91;</span><span class="br0">&#91;</span><span class="nu0">1</span>,<span class="nu0">2</span>,<span class="nu0">3</span><span class="br0">&#93;</span>,<span class="br0">&#91;</span><span class="nu0">4</span>,<span class="nu0">5</span>,<span class="nu0">6</span><span class="br0">&#93;</span>,<span class="br0">&#91;</span><span class="nu0">7</span>,<span class="nu0">8</span>,<span class="sy0">-</span><span class="nu0">9</span><span class="br0">&#93;</span><span class="br0">&#93;</span>
&nbsp;
<span class="br0">&#91;</span><span class="nu0">1</span> <span class="kw1">of</span> <span class="nu0">1</span><span class="br0">&#93;</span> Compiling Main &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span> main.hs, main.o <span class="br0">&#41;</span> 
Linking a.out ... &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
<span class="nu0">54.0</span></pre></td></tr></table></div></td></tr></tbody></table></div>Спасибо тем, кто дочитал до конца!<br />
<br />
Код можно скачать <a rel="nofollow noopener noreferrer" href="https://&quot;https://yadi.sk/d/Y-Vn5ouy83T13A&quot;" target="_blank" title="https://&quot;https://yadi.sk/d/Y-Vn5ouy83T13A&quot;"><b>здесь</b></a></div>

]]></content:encoded>
			<dc:creator>Catstail</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/226808/6721.html</guid>
		</item>
	</channel>
</rss>
