<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Zsombor Veres-Lakos]]></title><description><![CDATA[Zsombor Veres-Lakos]]></description><link>https://zsomborvereslakos.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!1f8A!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c08e8e6-68d1-440f-8638-ed3f6b7b9e1e_1281x1281.jpeg</url><title>Zsombor Veres-Lakos</title><link>https://zsomborvereslakos.substack.com</link></image><generator>Substack</generator><lastBuildDate>Thu, 23 Jul 2026 02:48:08 GMT</lastBuildDate><atom:link href="https://zsomborvereslakos.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Zsombor Veres-Lakos]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[zsomborvereslakos@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[zsomborvereslakos@substack.com]]></itunes:email><itunes:name><![CDATA[Zsombor Veres-Lakos]]></itunes:name></itunes:owner><itunes:author><![CDATA[Zsombor Veres-Lakos]]></itunes:author><googleplay:owner><![CDATA[zsomborvereslakos@substack.com]]></googleplay:owner><googleplay:email><![CDATA[zsomborvereslakos@substack.com]]></googleplay:email><googleplay:author><![CDATA[Zsombor Veres-Lakos]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Building a Sound-Based Anomaly Detector]]></title><description><![CDATA[After building an in-depth intuition of the CNN I decided to pursue a more practical challenge.]]></description><link>https://zsomborvereslakos.substack.com/p/ml-pipeline-for-the-mimii-dataset</link><guid isPermaLink="false">https://zsomborvereslakos.substack.com/p/ml-pipeline-for-the-mimii-dataset</guid><dc:creator><![CDATA[Zsombor Veres-Lakos]]></dc:creator><pubDate>Thu, 02 Jul 2026 06:58:11 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!lC5-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc54e455-6a8f-4154-8481-0e5309a0b344_1203x685.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>After building an in-depth intuition of the <a href="https://substack.com/home/post/p-190393845">CNN</a> I decided to pursue a more practical challenge. Implementing our own version of a model is a great way to build understanding but in the real world, professionals utilize well established tools. </p><p>For this I selected the <a href="https://zenodo.org/records/3384388">MIMII dataset</a> (malfunctioning industrial machine investigation and inspection). This dataset contains several industrial machine sounds (fan, pump, valve). Each is labeled as normal or abnormal operation. The challenge is to build a model that can label the incoming audio to predict whether the machine is in a normal or abnormal state. </p><p>I built a CNN-based autoencoder model &#8212; an unsupervised architecture that learns two functions: an encoder that compresses the input into a compact representation, and a decoder that reconstructs the original input from that representation. The goal is to learn an efficient internal encoding of the data without requiring labeled examples.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lC5-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc54e455-6a8f-4154-8481-0e5309a0b344_1203x685.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lC5-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc54e455-6a8f-4154-8481-0e5309a0b344_1203x685.png 424w, https://substackcdn.com/image/fetch/$s_!lC5-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc54e455-6a8f-4154-8481-0e5309a0b344_1203x685.png 848w, https://substackcdn.com/image/fetch/$s_!lC5-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc54e455-6a8f-4154-8481-0e5309a0b344_1203x685.png 1272w, https://substackcdn.com/image/fetch/$s_!lC5-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc54e455-6a8f-4154-8481-0e5309a0b344_1203x685.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lC5-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc54e455-6a8f-4154-8481-0e5309a0b344_1203x685.png" width="1203" height="685" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bc54e455-6a8f-4154-8481-0e5309a0b344_1203x685.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:685,&quot;width&quot;:1203,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!lC5-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc54e455-6a8f-4154-8481-0e5309a0b344_1203x685.png 424w, https://substackcdn.com/image/fetch/$s_!lC5-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc54e455-6a8f-4154-8481-0e5309a0b344_1203x685.png 848w, https://substackcdn.com/image/fetch/$s_!lC5-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc54e455-6a8f-4154-8481-0e5309a0b344_1203x685.png 1272w, https://substackcdn.com/image/fetch/$s_!lC5-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc54e455-6a8f-4154-8481-0e5309a0b344_1203x685.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><a href="https://medium.com/data-science/applied-deep-learning-part-3-autoencoders-1c083af4d798">Autoencoder model</a></figcaption></figure></div><p>In my concrete use case, this means I first trained only on normal data. The loss of the model&#8217;s output is low. Then, if I give the model an abnormal audio sample, the loss should be high, since it does not know how to decode abnormal samples.</p><p>I first preprocessed the data with Torchaudio&#8217;s mel spectrogram. A spectrogram shows the frequencies that make up the sound, from low to high, and how they change over time, from left to right. Then I forwarded this image to the CNN model. I used the <a href="https://docs.pytorch.org/docs/2.12/generated/torch.nn.Conv2d.html">PyTorch's implementation</a>. The model got progressively downsampled.</p><p>I got 0.98 AUC on the fan id_02 dataset  compared to a baseline AUC of 0.99 reported in <a href="https://arxiv.org/pdf/1909.09347">research paper</a>. Using a trivial model like measuring loudness, I got only 0.40 AUC on the fan dataset.</p><p>I used wandb to track training metrics and experiment with different thresholds, but eventually I set the threshold at the 90th percentile of reconstruction error on normal data &#8212; any sample with higher loss is flagged as anomalous. </p><p>Eventually I exported the model to ONNX format and I published it to <a href="https://huggingface.co/spaces/vlzsombor/mimii">Hugging Face Space</a> using the Gradio frontend library. As is visible in the Hugging Face repository I also dockerized and published the model with FastAPI. Lastly I added Prometheus and Grafana in order to experiment with metrics collection.</p><p>In this <a href="https://github.com/vlzsombor/mimii">project</a> I tried to use as many professional tools as possible. </p><ul><li><p><strong>Weights &amp; Biases (W&amp;B):</strong> Learned to track training runs, compare hyperparameter sweeps, and visualize threshold selection instead of relying on printed logs.</p></li><li><p><strong>ONNX:</strong> Learned to export a PyTorch model into a framework-agnostic format for portable inference outside the training environment.</p></li><li><p><strong>Gradio:</strong> Learned to wrap a model in a minimal web UI.</p></li><li><p><strong>FastAPI:</strong> Learned to expose the model as a REST endpoint.</p></li><li><p><strong>Prometheus+Grafana</strong>: Learned to collect, store and visualize live inference metrics from a running service</p></li></ul><p>Most of them were so-called &#8216;unknown unknowns&#8217;, meaning I did not even know that they existed. With this challenge next time I will be able to use these tools more thoughtfully.</p>]]></content:encoded></item><item><title><![CDATA[I implemented convolutional neural network in rust from scratch.]]></title><description><![CDATA[I implemented convolutional neural network from scratch in rust. I reached accuracy of 93% on the Kaggle&#8217;s competition with only training on 2000 samples.]]></description><link>https://zsomborvereslakos.substack.com/p/i-implemented-convolutional-neural</link><guid isPermaLink="false">https://zsomborvereslakos.substack.com/p/i-implemented-convolutional-neural</guid><dc:creator><![CDATA[Zsombor Veres-Lakos]]></dc:creator><pubDate>Wed, 06 May 2026 06:08:37 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!D3eZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeb088d3-141d-4bd6-8994-a9525648f951_1459x1078.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a href="https://github.com/vlzsombor/cnn-from-scratch">I implemented convolutional neural network from scratch in rust.</a> I reached accuracy of 93% on the <a href="https://www.kaggle.com/competitions/digit-recognizer/submissions#">Kaggle&#8217;s competition</a> with only training on 2000 samples. The results lay below a well-tuned MLP (~98%), but a meaningful result given the constraint.</p><p>I mostly relied on the &#8220;Derivation of backpropagation in convolutional neural network (cnn)&#8221; paper by Zhang, Zhifei.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!D3eZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeb088d3-141d-4bd6-8994-a9525648f951_1459x1078.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!D3eZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeb088d3-141d-4bd6-8994-a9525648f951_1459x1078.png 424w, https://substackcdn.com/image/fetch/$s_!D3eZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeb088d3-141d-4bd6-8994-a9525648f951_1459x1078.png 848w, https://substackcdn.com/image/fetch/$s_!D3eZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeb088d3-141d-4bd6-8994-a9525648f951_1459x1078.png 1272w, https://substackcdn.com/image/fetch/$s_!D3eZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeb088d3-141d-4bd6-8994-a9525648f951_1459x1078.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!D3eZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeb088d3-141d-4bd6-8994-a9525648f951_1459x1078.png" width="728" height="538" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aeb088d3-141d-4bd6-8994-a9525648f951_1459x1078.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:1076,&quot;width&quot;:1456,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:1665751,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://zsomborvereslakos.substack.com/i/190393845?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeb088d3-141d-4bd6-8994-a9525648f951_1459x1078.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!D3eZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeb088d3-141d-4bd6-8994-a9525648f951_1459x1078.png 424w, https://substackcdn.com/image/fetch/$s_!D3eZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeb088d3-141d-4bd6-8994-a9525648f951_1459x1078.png 848w, https://substackcdn.com/image/fetch/$s_!D3eZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeb088d3-141d-4bd6-8994-a9525648f951_1459x1078.png 1272w, https://substackcdn.com/image/fetch/$s_!D3eZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faeb088d3-141d-4bd6-8994-a9525648f951_1459x1078.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><strong><a href="https://youtu.be/H0oEr40YhrQ">Convolutional Network Demo from 1989 [restored version]</a></strong></figcaption></figure></div><p><em>Why from scratch?</em></p><p>I want to understand the inner mechanisms of neural networks. Using high-level libraries (such as PyTorch) without understanding what happens internally can lead to the illusion of understanding. One might start to believe that building a neural network is simply a matter of writing a few lines of code, rather than understanding the underlying concepts. Implementing a model from scratch makes these computations explicit and exposes details that would otherwise be hidden.</p><p><em>Why in rust?</em></p><p>I selected rust because I am already quite fluent in C# and wanted to learn a programming language with zero cost abstraction. C++ has a messy ecosystem, I think the ecosystem would have taken away the focus from the already hard system-programming-language concepts. In hindsight I had zero difficulty with Rust&#8217;s ecosystem, so my choice seems to be justified.</p><p><em>The model:</em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HvNX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1a33ee-b159-46fd-a4c4-c0b4a7308424_1815x606.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HvNX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1a33ee-b159-46fd-a4c4-c0b4a7308424_1815x606.png 424w, https://substackcdn.com/image/fetch/$s_!HvNX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1a33ee-b159-46fd-a4c4-c0b4a7308424_1815x606.png 848w, https://substackcdn.com/image/fetch/$s_!HvNX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1a33ee-b159-46fd-a4c4-c0b4a7308424_1815x606.png 1272w, https://substackcdn.com/image/fetch/$s_!HvNX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1a33ee-b159-46fd-a4c4-c0b4a7308424_1815x606.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HvNX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1a33ee-b159-46fd-a4c4-c0b4a7308424_1815x606.png" width="1456" height="486" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/af1a33ee-b159-46fd-a4c4-c0b4a7308424_1815x606.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:486,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:152228,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://zsomborvereslakos.substack.com/i/190393845?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1a33ee-b159-46fd-a4c4-c0b4a7308424_1815x606.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!HvNX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1a33ee-b159-46fd-a4c4-c0b4a7308424_1815x606.png 424w, https://substackcdn.com/image/fetch/$s_!HvNX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1a33ee-b159-46fd-a4c4-c0b4a7308424_1815x606.png 848w, https://substackcdn.com/image/fetch/$s_!HvNX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1a33ee-b159-46fd-a4c4-c0b4a7308424_1815x606.png 1272w, https://substackcdn.com/image/fetch/$s_!HvNX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faf1a33ee-b159-46fd-a4c4-c0b4a7308424_1815x606.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The structure of CNN example that will be discussed in this paper. It is exactly the same to the structure used in the demo of Matlab DeepLearnToolbox. <em>(from the paper)</em></figcaption></figure></div><p>This figure defines a CNN model with 2 convolutional layer with sigmoid activation layer and two average pooling layer, and one linear layer.</p><ol><li><p>The first convolution layer&#8217;s kernel has 1 channel, 6 filters and the size is 5x5.</p></li><li><p>The pooling layer averages each 2&#215;2 region into a single value, halving the input in both height and width</p></li><li><p>The second convolution layer&#8217;s kernel has 6 channel, 12 filters and the size of 5x5</p></li><li><p>The same average pooling layer as the first one</p></li><li><p>The final linear network part has 10x192 size meaning it takes 192 input and converts it to 10 output corresponding to the 10 digits.</p></li><li><p>Although the paper uses sigmoid activation in the final layer with mean squared error cost function, I decided to use cross entropy loss with softmax function.</p></li></ol><p>The model did not visibly overfit. Possible contributing factors are small parameter count (3898), polling layer discarding image noise, and Xavier initialization stabilizing early training.</p><p>I tried to write a relatively clean code for easily model extendibility. Being my first Rust project, I was not able to write fully idiomatic code &#8212; for example, I relied on .clone() more than ownership rules would require. Still I managed a clean extendable code:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;rust&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-rust">        let kernel: Array4&lt;f32&gt; = {
            xavier2(&amp;[1, 6, 5, 5]) // [channel, filter, height, width
                                   // as in the model description figure: 
                                   // 1 channel, 6 filter, 5x5
                .into_dimensionality::&lt;ndarray::Ix4&gt;()
                .expect("kernel initialization failed")
        };

        let kernel2: Array4&lt;f32&gt; = {
            xavier2(&amp;[6, 12, 5, 5])
                .into_dimensionality::&lt;ndarray::Ix4&gt;()
                .expect("kernel initialization failed")
        };

        let layers: Vec&lt;Box&lt;dyn CnnLayerable&gt;&gt; = vec![
            Box::new(ConvolutionalMatlab::new(kernel, alpha)),
            Box::new(CnnSigmoidActivation::new()),
            Box::new(CnnPoolingLayer::new()),
            Box::new(ConvolutionalMatlab::new(kernel2, alpha)),
            Box::new(CnnSigmoidActivation::new()),
            Box::new(CnnPoolingLayer::new()),
        ];
        let linear_layers: Vec&lt;Box&lt;dyn Layerable&gt;&gt; = vec![
            Box::new(Layer::new(192, 10, alpha)),
            //Box::new(ActivationLayer::sigmoid())-&gt; I removed for cross entropy loss + softmax
        ];</code></pre></div><p>In the code above I show that adding a new layer is only a adding an extra line of code. </p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;rust&quot;,&quot;nodeId&quot;:null}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-rust">//For linear layers
pub trait Layerable: fmt::Debug{
    fn forward(&amp;mut self, x: &amp;Array2&lt;f32&gt;) -&gt; Array2&lt;f32&gt;;
    fn backward_propagation(&amp;mut self, dc_da: &amp;Array2&lt;f32&gt;) -&gt; Array2&lt;f32&gt;;
}
//For convolutional layers
pub trait CnnLayerable: fmt::Debug{
    fn forward_propagation(&amp;mut self, x: &amp;ImageData) -&gt; Array3&lt;f32&gt;;
    fn backward_propagation(&amp;mut self, delta_c: &amp;ImageData) -&gt; Array3&lt;f32&gt;;
}</code></pre></div><p>I made it extensible using traits. Each layer implements one of these traits. For forward propagation, I simply execute forward_propagation on each layer in order, for backpropagation, I call backward_propagation in reverse.</p><p>With a linear neural network, using 2D matrices for inputs and outputs seemed reasonable. Only when I started implementing the convolutional part did I realize that a CNN actually needs 3D matrices. I didn&#8217;t want to break my working code, so I created a new trait. By the end of the project, I also realized that for better performance I should be using 4D matrices (the extra dimension being the batch size). If I rewrote this project, I would be using a single trait that works across different matrix dimensions.</p><p><em>CNN Insights:</em></p><ul><li><p>I realized that the standard CNN implementations most of the time does not utilize convolution, but cross correlation<strong>. </strong>The difference being that cross correlation does not mirrors the kernel. It has no practical effect on the training but still important to pinpoint out for mathematical correctness.</p></li><li><p>Most of the time the neural network is depicted the following way. This is actually wrong. In reality every node has a bias term.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!D2lc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7c1e50-451b-473d-91ff-4b00e5322926_847x713.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!D2lc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7c1e50-451b-473d-91ff-4b00e5322926_847x713.png 424w, https://substackcdn.com/image/fetch/$s_!D2lc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7c1e50-451b-473d-91ff-4b00e5322926_847x713.png 848w, https://substackcdn.com/image/fetch/$s_!D2lc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7c1e50-451b-473d-91ff-4b00e5322926_847x713.png 1272w, https://substackcdn.com/image/fetch/$s_!D2lc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7c1e50-451b-473d-91ff-4b00e5322926_847x713.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!D2lc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7c1e50-451b-473d-91ff-4b00e5322926_847x713.png" width="276" height="232.3353010625738" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bc7c1e50-451b-473d-91ff-4b00e5322926_847x713.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:713,&quot;width&quot;:847,&quot;resizeWidth&quot;:276,&quot;bytes&quot;:201508,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://zsomborvereslakos.substack.com/i/190393845?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7c1e50-451b-473d-91ff-4b00e5322926_847x713.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:&quot;center&quot;,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!D2lc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7c1e50-451b-473d-91ff-4b00e5322926_847x713.png 424w, https://substackcdn.com/image/fetch/$s_!D2lc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7c1e50-451b-473d-91ff-4b00e5322926_847x713.png 848w, https://substackcdn.com/image/fetch/$s_!D2lc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7c1e50-451b-473d-91ff-4b00e5322926_847x713.png 1272w, https://substackcdn.com/image/fetch/$s_!D2lc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc7c1e50-451b-473d-91ff-4b00e5322926_847x713.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Incorrect bias representation</figcaption></figure></div><ul><li><p>As I already implemented the linear network part, I knew how subtle bugs can be in backpropagation. To minimalize the headache I added gradient check as a unit test. It is basically a mathematically proved &#8220;debugging tool&#8221;. It works by comparing the analytical gradients (computed by backprop) against numerical gradients (approximated using small perturbations to the weights). If the two match closely, your backprop is likely correct. If they don't, you know there's a bug in your derivative calculations.</p></li><li><p>Gradient check helped me identifying a bug in my sigmoid activation layer. Although the loss function&#8217;s value decreased in the first hundred epochs it started to grow significantly afterwards. At first I thought it must have happened because of the learning rate being too great. Eventually it turned out that I implemented the sigmoid activation function incorrectly. </p><p>The correct equation would be:</p><pre><code><code>delta_l = sigma'(a_l) &#8857; delta_(l+1)</code></code></pre><p>Where a_l is the cached output of the forward pass and delta_(l+1) is the incoming gradient from the next layer and sigma&#8217;() is the sigmoid&#8217;s derivative function.<br>Instead of the equation above I implemented the following equation</p><pre><code><code>delta_l = sigma'(delta_(l+1))</code></code></pre></li></ul><p><em>Rust insights:</em></p><p>I enjoyed to program in rust. It clarified a lot in the inner working of C# as well. Such clarifications were:</p><ul><li><p>In C#, interface dispatch is always virtual (runtime). In Rust you choose explicitly: <code>dyn Trait</code> gives dynamic dispatch via a fat pointer (data pointer + vtable pointer, type erased), <code>impl Trait</code> or a generic <code>&lt;T: Trait&gt;</code> gives static dispatch, where the compiler generates a separate concrete function per type at compile time.</p></li></ul><ul><li><p>I C# the garbage collector collects the unused references automatically. It guarantees memory safety on the expense of performance. With rust adhering to a few rules you can have a same effect without performance erosion. It takes a while until one get use to these rules. However all effort is compensated in the moment of running the application in release mode knowing that language&#8217;s abstractions have no runtime overhead.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Cq_E!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c7d5a4c-5d3c-43c2-bae1-97cfb3e66a48_1731x856.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Cq_E!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c7d5a4c-5d3c-43c2-bae1-97cfb3e66a48_1731x856.png 424w, https://substackcdn.com/image/fetch/$s_!Cq_E!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c7d5a4c-5d3c-43c2-bae1-97cfb3e66a48_1731x856.png 848w, https://substackcdn.com/image/fetch/$s_!Cq_E!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c7d5a4c-5d3c-43c2-bae1-97cfb3e66a48_1731x856.png 1272w, https://substackcdn.com/image/fetch/$s_!Cq_E!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c7d5a4c-5d3c-43c2-bae1-97cfb3e66a48_1731x856.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Cq_E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c7d5a4c-5d3c-43c2-bae1-97cfb3e66a48_1731x856.png" width="1456" height="720" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5c7d5a4c-5d3c-43c2-bae1-97cfb3e66a48_1731x856.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:720,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:206218,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://zsomborvereslakos.substack.com/i/190393845?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c7d5a4c-5d3c-43c2-bae1-97cfb3e66a48_1731x856.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Cq_E!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c7d5a4c-5d3c-43c2-bae1-97cfb3e66a48_1731x856.png 424w, https://substackcdn.com/image/fetch/$s_!Cq_E!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c7d5a4c-5d3c-43c2-bae1-97cfb3e66a48_1731x856.png 848w, https://substackcdn.com/image/fetch/$s_!Cq_E!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c7d5a4c-5d3c-43c2-bae1-97cfb3e66a48_1731x856.png 1272w, https://substackcdn.com/image/fetch/$s_!Cq_E!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c7d5a4c-5d3c-43c2-bae1-97cfb3e66a48_1731x856.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Zhang, Zhifei. &#8220;Derivation of backpropagation in convolutional neural network (cnn).&#8221; University of Tennessee, Knoxville, TN 22.23 (2016): 4.</p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[Implementing an equation parser using functional paradigm]]></title><description><![CDATA[A Transition from C# to F#]]></description><link>https://zsomborvereslakos.substack.com/p/implementing-an-abstract-syntax-tree</link><guid isPermaLink="false">https://zsomborvereslakos.substack.com/p/implementing-an-abstract-syntax-tree</guid><dc:creator><![CDATA[Zsombor Veres-Lakos]]></dc:creator><pubDate>Sat, 21 Feb 2026 08:47:20 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!1f8A!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c08e8e6-68d1-440f-8638-ed3f6b7b9e1e_1281x1281.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently, I have become interested in functional paradigms. Learning about it makes me rethink my inner intuition of C# and programming in general.  I simply prompted an LLM agent for simple project ideas that would improve my beginner functional programming skill. At first I implemented small projects like writing a kanban board with console UI. </p><p>Then I started a project to build a simple equation parser to convert expressions into an abstract syntax tree for calculating the expression. (Supporting + - * / and () operators with * / having operator precedence)</p><p>I tried to minimize the help coming from outer sources and maximize my own ingenuity. I only knew the application should have a string mathematical expression as an input and its result as output. My only clue for building a tree structure was the project name itself. It took multiple attempts before I figured out what a reasonable architecture could be. Initially I thought I can finish it within a few hours, eventually I needed a week with a few hours of work every day.</p><p>Learning about F# (or another functional programming language alike) helps a lot adopting modern C# techniques.  It is not a coincidence that most of the modern C# features are actually coming from the functional paradigm. (lambda, higher order function, records, switch expression).</p><p>Functional Programming (FP) and Object-Oriented Programming (OOP) solve the same problems using fundamentally different abstractions. I felt as if I had to adopt a new thinking, orthogonal to the typical OOP solution. </p><p>OOP emphasizes nouns. What should achieve something, the verbs (methods) can only exist in relation to the noun. It tends to be stateful because it models systems as objects that change their internal data over time. Any instance method has implicitly the this parameter allowing changes in the object state.</p><p>On the other hand FP emphasizes verbs that act on immutable data transformations rather than state changes. It transforms, combines, or analyzes data without causing side effects.</p><p>What I like more in FP:</p><p>* No exceptions but discriminated unions: Exceptions are avoided in functional programming because hidden outputs break referential transparency. FP utilizes the Result pattern, where a function returns either a value or an error type. On the caller side, you must use pattern matching to handle every case. While this remotely resembles &#8220;throwing and catching an exception,&#8221; there is a fundamental difference. With exception the return type does not encode the error case. You no longer get a well-defined result from the method because errors are not part of the return type. I believe the Java development team tried to solve this by adding checked exceptions. However, this approach makes things worse, as checked exceptions violate the Open/Closed Principle. Every intermediate layer must be adjusted when changes occur, even if it doesn&#8217;t handle the error itself. In C#, a common solution is using helper NuGet packages such as <a href="https://www.nuget.org/packages/OneOf">OneOf</a>.</p><p>Example:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;csharp&quot;,&quot;nodeId&quot;:&quot;c16bc876-6b84-4fb7-a77a-185b46306431&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-csharp">//typical approach

public int BusinessLogic(Tree&lt;AstNode&gt; tree){
    //If cannot cast exception is thrown
    //The method no longer has a well defined behavior for every input
    //The unhappy paths can be handled with statements
    Operator op = (Operator)tree;
    //logic

}</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;e3d0a3cb-c9b5-4431-82d8-493d22eeef26&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">let rec CalculateTree (tree: Tree&lt;AstNode&gt;) =
    match tree with
    | Leaf(Number n) -&gt; Ok n
    | Node(Operator operator, left, right) -&gt;
        match CalculateTree left, CalculateTree right with
        | Ok l, Ok r -&gt; Ok(operator.Calculate l r)
        | _ -&gt; Error &#8220;Incorrect abstract syntax tree&#8221;
    | _ -&gt; Error &#8220;Incorrect abstract syntax tree&#8221;

# Consume:

    match CalculateTree lastOperator with
    | Ok resultValue -&gt; printfn $&#8221;Happy path the number is: %d{resultValue}&#8221;
    | Error errorValue -&gt; printfn $&#8221;Unhappy path, %s{errorValue}&#8221;</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;csharp&quot;,&quot;nodeId&quot;:&quot;240159e4-136d-4bac-81cb-3ae415f3141e&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-csharp">//Psuedo Result class

public Result&lt;int&gt; BusinessLogic(Tree&lt;AstNode&gt; tree){
    Operator op = tree as Operator;
    if(op is null) {
        return Errors(&#8220;unhappy path with an error&#8221;)
    }
    //logic
    return Ok(number);

}

public void Calculate(){
    var result = BusinessLogic(MyAstNodes);
    if(result.IsError){

    }
}</code></pre></div><p>* Higher order function: until I learned about functional programming I didn&#8217;t realize that higher order functions can replace most of the popular programming loops. I over used for loops when a mapping (select) would have been a much more appropriate choice. I was not aware just how versatile higher-order functions can be.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;csharp&quot;,&quot;nodeId&quot;:&quot;01c97e18-c468-4deb-b0dc-7d6ee3a0fe49&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-csharp">public IEnumerable&lt;int&gt; MappingWithStatements(IEnumerable&lt;int&gt; myNumbers){
    List&lt;int&gt; returnList = new List&lt;int&gt;();
    foreach(var number in myNumbers){
        if(number == 42){
            //Filtering
            continue;
        }
        var numberWithTransformation = number * 2;
        returnList.Add(numberWithTransformation)
    }
    return returnList;
}

public IEnumerable&lt;int&gt; MappingWithExpression(IEnumerable&lt;int&gt; myNumbers) 
    =&gt; myNumbers
        .Where(number =&gt; number != 7)
        .Select(number =&gt; number*2)</code></pre></div><p>Before reflecting on higher order function I would not realize that these two code describes the same thing, the second using a much concise syntax.</p><p>* Pipe operators: C# does not have a universal pipe operator for arbitrary functions, so chained function must be read backwards.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;csharp&quot;,&quot;nodeId&quot;:&quot;6af98a35-095e-4375-a96d-098e8863571f&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-csharp">buildTree(getTokens(input).ToList())</code></pre></div><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;f3b6ca87-1981-45c0-99bc-ec1a864f7b7d&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">let main2 (input: string) =
    input
    |&gt; getTokens
    |&gt; Seq.toList
    |&gt; buildTree</code></pre></div><p></p><p>Luckily it doesn&#8217;t apply to Linq functions and you can easily define your own mini <a href="https://dev.to/ivypuckett/introducing-c-pipe-extensions-5d0j">Pipe operator</a> anyway.</p><p>* Statements: Historically C# is a statement based language, but it is moving toward expressions. (opposed to F#). In modern C#, expression should almost always be favored to statements. There is more and more support for expression in every newer version of the language (Such as the switch expression) Of course within reasonable limits, for instance it would be awkward to use .ContinueWith() instead of using await.</p><p>What I disliked:</p><p>* Recursive functions/learning the loop replacement: Imperative languages rely on a few general-purpose loop constructs, functional programming uses a broader library of specialized higher-order functions and recursion. This requires a steeper initial learning curve, and takes time to get used to recursion but also shifts the developer&#8217;s focus from manual iteration logic to high-level data transformation patterns. </p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;5205505d-ef99-4f9c-963c-09c9c89cdb1d&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">let groupTokens (tokens: string list) =
    let rec parse current (remaining: string list) =
        match remaining with
        | [] -&gt; List.rev current, []
        | &#8220;)&#8221; :: tail -&gt; List.rev current, tail
        | &#8220;(&#8221; :: tail -&gt;
            let inner, next = parse [] tail
            parse (Group inner :: current) next
        | token :: tail -&gt; parse (Scalar(strToOperator token) :: current) tail

    let result, _ = parse [] tokens
    result</code></pre></div><p>In idiomatic functional programming there are no loops, recursion is used for achieving its effect. It was the first time I have seen this &#8220;pattern&#8221;. With an immature team it slows the development time down.</p><p>My repository is <a href="https://github.com/vlzsombor/fsharp_algebra_ast">available here</a>.</p>]]></content:encoded></item></channel></rss>