<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nick Tchayka</title>
    <description>The latest articles on DEV Community by Nick Tchayka (@nickseagull).</description>
    <link>https://dev.to/nickseagull</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F10745%2F2773d0e1-499e-4440-a91c-2e845d1b9325.png</url>
      <title>DEV Community: Nick Tchayka</title>
      <link>https://dev.to/nickseagull</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nickseagull"/>
    <language>en</language>
    <item>
      <title>Going Full-Time NeoHaskell</title>
      <dc:creator>Nick Tchayka</dc:creator>
      <pubDate>Tue, 04 Nov 2025 10:04:34 +0000</pubDate>
      <link>https://dev.to/neohaskell/going-full-time-neohaskell-1ib</link>
      <guid>https://dev.to/neohaskell/going-full-time-neohaskell-1ib</guid>
      <description>&lt;p&gt;So here's what's been happening lately. After my contract ended with my last client, I decided to take a different path than usual. Instead of immediately jumping into the next opportunity, I'm working on NeoHaskell full-time while living off my savings.&lt;/p&gt;

&lt;p&gt;I know that might sound concerning to some, but there's actually a solid plan behind this decision. The goal is straightforward: turn NeoHaskell into something that can sustain itself financially. Not just as a hobby project, but as something I can actually live from.&lt;/p&gt;

&lt;p&gt;The approach I'm taking is very production-focused. I'm starting with the core infrastructure that any real application needs - an event store built on PostgreSQL. Nothing experimental or overly clever, just reliable technology that works. After that comes the command handling and read models. These might not be the most exciting features to talk about, but they're what you need to actually ship software.&lt;/p&gt;

&lt;p&gt;To help make this sustainable, I've opened several ways to support the project: &lt;a href="https://opencollective.com/neohaskell" rel="noopener noreferrer"&gt;Open Collective&lt;/a&gt;, &lt;a href="https://ko-fi.com/nickseagull" rel="noopener noreferrer"&gt;Ko-fi&lt;/a&gt;, &lt;a href="https://github.com/sponsors/NickSeagull" rel="noopener noreferrer"&gt;GitHub Sponsors&lt;/a&gt;, and a few others. Every contribution helps keep this going.&lt;/p&gt;

&lt;p&gt;What makes me optimistic about this path is that I already have a prospect client who's committed to using NeoHaskell for their project. This is huge because it means every feature I'm building is being validated against real production needs. Instead of guessing what developers might want, I'm implementing what someone actually needs to ship their product.&lt;/p&gt;

&lt;p&gt;This client-first approach is shaping the project in really positive ways. I'm focusing on the leanest possible changes that deliver immediate value. Every addition to the language and ecosystem is driven by actual requirements, not theoretical possibilities. This constraint is exactly what NeoHaskell needs right now.&lt;/p&gt;

&lt;p&gt;I'm also offering consulting services around NeoHaskell and event-driven architectures. If you're curious about using NeoHaskell for your project or want help with event sourcing in general, I'd be happy to chat.&lt;/p&gt;

&lt;p&gt;The next few months are going to be interesting. Working on NeoHaskell full-time means I can finally give it the attention it deserves. The event store is coming along nicely, and with real production use cases driving development, I'm confident we're building something genuinely useful.&lt;/p&gt;

&lt;p&gt;Thanks for following along on this journey. Whether you're contributing code, supporting financially, or just keeping up with the updates, you're helping make this project real.&lt;/p&gt;

</description>
      <category>career</category>
      <category>programming</category>
      <category>haskell</category>
      <category>opensource</category>
    </item>
    <item>
      <title>🚀 Introducing `neo`: A CLI Tool for Your NeoHaskell Projects</title>
      <dc:creator>Nick Tchayka</dc:creator>
      <pubDate>Thu, 27 Mar 2025 20:09:00 +0000</pubDate>
      <link>https://dev.to/neohaskell/introducing-neo-a-cli-tool-for-your-neohaskell-projects-58gp</link>
      <guid>https://dev.to/neohaskell/introducing-neo-a-cli-tool-for-your-neohaskell-projects-58gp</guid>
      <description>&lt;p&gt;We're excited to announce the release of &lt;strong&gt;&lt;code&gt;neo&lt;/code&gt;&lt;/strong&gt;, the official command-line interface for &lt;strong&gt;NeoHaskell&lt;/strong&gt; — a growing dialect of Haskell focused on clarity, composability, and modern tooling.&lt;/p&gt;

&lt;p&gt;This release marks a major milestone: for the first time, you can create, build, and run a NeoHaskell project from the terminal using a single tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚡ What Can &lt;code&gt;neo&lt;/code&gt; Do?
&lt;/h2&gt;

&lt;p&gt;The current version of the CLI supports three core commands to help you get started fast:&lt;/p&gt;

&lt;h3&gt;
  
  
  🆕 &lt;code&gt;neo new -n "my-project"&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Generates a new NeoHaskell project scaffold with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;MainModule.hs&lt;/code&gt; entry point&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;neo.json&lt;/code&gt; configuration file&lt;/li&gt;
&lt;li&gt;A clean layout with everything you need to start writing NeoHaskell code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just run the command and start coding—no boilerplate or manual setup needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔨 &lt;code&gt;neo build&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Compiles your project using NeoHaskell’s internal build pipeline.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Note:&lt;/strong&gt; The build process is currently slower than ideal.&lt;br&gt;&lt;br&gt;
We’re aware of the bottlenecks and have improvements scheduled for future sprints.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  ▶️ &lt;code&gt;neo run&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Runs your compiled project. This command wires everything together and launches your NeoHaskell program with zero configuration.&lt;/p&gt;

&lt;p&gt;Perfect for quick feedback loops and iterative experimentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧪 Try It Out
&lt;/h2&gt;

&lt;p&gt;You can install &lt;code&gt;neo&lt;/code&gt; and create your first project in seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--proto&lt;/span&gt; &lt;span class="s1"&gt;'=https'&lt;/span&gt; &lt;span class="nt"&gt;--tlsv1&lt;/span&gt;.2 &lt;span class="nt"&gt;-sSf&lt;/span&gt; https://sh.neohaskell.org | bash
neo new &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"my-project"&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;my-project
neo build
neo run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🛤️ What’s Next?
&lt;/h2&gt;

&lt;p&gt;With the foundational CLI in place, the next sprint will focus on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📦 Designing the &lt;strong&gt;project structure&lt;/strong&gt; and conventions for NeoHaskell's built-in &lt;strong&gt;event sourcing framework&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;🧱 Scaffolding support for events, commands, and read-models&lt;/li&gt;
&lt;li&gt;✨ Adding commands like &lt;code&gt;neo generate&lt;/code&gt; to create components and wire them into your application automatically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is to make event-driven apps idiomatic and ergonomic in NeoHaskell—without requiring external libraries or complex setups.&lt;/p&gt;

&lt;h2&gt;
  
  
  🪞 Retrospective on Sprint 1
&lt;/h2&gt;

&lt;p&gt;Well, I’ve completed the first sprint of NeoHaskell. The experience has been pretty good—it gave me a block of time where I could say, “Okay, I commit to these tasks,” and that helped me avoid falling into the endless loop of optimization and perfectionism, which is probably what kills a lot of projects like this.&lt;/p&gt;

&lt;p&gt;It’s also helped a lot in starting to treat NeoHaskell as an investment project. Ultimately, it’s something I’d really like to see succeed, and ideally, I’d love for it to become a tool I use to create products—something that allows me to build full-stack apps ten times faster than any tool currently on the market. Of course, it will have trade-offs like any tool—there’s no silver bullet—but a boost in productivity is very likely. This is something I already achieved when I worked with the Booster Framework team, and I think integrating that into a programming language with the vision of NeoHaskell is absolutely possible.&lt;/p&gt;

&lt;p&gt;Back to the sprint: things I liked — I enjoyed giving the sprint a theme. The goal of this first sprint was to have an MVP of the NeoHaskell CLI tool. And an MVP is just that—&lt;em&gt;minimum&lt;/em&gt;. Like LinkedIn’s former CEO said: if you're proud of what you’ve just launched, then you launched too late. And I’m definitely &lt;em&gt;not&lt;/em&gt; proud of the MVP of the NeoHaskell CLI 😅 but hey, there’s now a tool that, despite being slow and not offering the best user experience yet, allows you to compile, run, and create NeoHaskell projects easily.&lt;/p&gt;

&lt;p&gt;Also, the installer now supports a one-click install and integrates with Nix. So behind the scenes, there's already quite a bit of machinery in place to make future configuration and extensions easier.&lt;/p&gt;

&lt;p&gt;Things that didn’t go as well — I’m not sure if a two-week sprint is the right cadence. Less than that feels too rushed to match the theme, but two weeks might be dragging it a bit too much. Still, I’ll stick with two weeks for now and see how it goes.&lt;/p&gt;

&lt;p&gt;For the future, I want to keep the practice of having just a few tasks in each sprint. This time, it coincided with a very intense work period, which drained my energy to contribute as much as I wanted. But thanks to keeping the sprint scope really tight—and keeping the tasks small—I was able to make it satisfying.&lt;/p&gt;

&lt;p&gt;For the next sprint, I want to start rethinking the core framework of NeoHaskell. Right now, it’s heavily inspired by Elm, and while that’s fine, I’d like to shift more toward &lt;strong&gt;event modeling&lt;/strong&gt;. That could make it easier to design and architect projects. These two approaches aren’t mutually exclusive, of course, so for Sprint 2, the theme will be to have at least a basic &lt;strong&gt;event modeling&lt;/strong&gt; plan in place.&lt;/p&gt;

&lt;p&gt;I’m not totally sure how I’ll break that down into tasks yet, especially in terms of code, but at the very least I’ll work on it and hopefully generate some documentation around it.&lt;/p&gt;

&lt;p&gt;To sum up Sprint 1: aside from deprioritizing the REPL task (because I think it's more valuable to focus on solidifying the &lt;strong&gt;event modeling / event sourcing&lt;/strong&gt; foundation for now), I’m happy with the results. Once that base is solid, the CLI structure can be rethought. We might even get to a point where there’s a &lt;code&gt;neodev&lt;/code&gt; command to run the project in development mode—which would include executing the &lt;code&gt;main&lt;/code&gt;, and potentially having a REPL for exploring and testing functions interactively.&lt;/p&gt;

&lt;p&gt;In the future, this could even open the door to more tooling around &lt;strong&gt;event sourcing&lt;/strong&gt;, like a debugger that works like a time machine, or a way to visualize the project architecture.&lt;/p&gt;

&lt;p&gt;But for now, there &lt;em&gt;is&lt;/em&gt; a working CLI—it’s not perfect, but it works, it installs, and it does what it’s supposed to. For the next sprint, I’ll be doing the same: building something that works as a solid base, this time for the NeoHaskell framework itself.&lt;/p&gt;

&lt;p&gt;That’s the update—I hope you're as excited as I am. Let’s keep going and bring the best programming language ever into existence.&lt;/p&gt;

&lt;p&gt;Want to help shape the future of NeoHaskell? We’re building it in the open—contributions, feedback, and ideas are all welcome. Jump into the &lt;a href="https://github.com/neohaskell/neohaskell" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt; or join our &lt;a href="https://discord.com/invite/wDj3UYzec8" rel="noopener noreferrer"&gt;Discord server&lt;/a&gt; to connect with the community.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>opensource</category>
      <category>haskell</category>
    </item>
    <item>
      <title>Hypersigilating NeoHaskell and Speedrunning Life</title>
      <dc:creator>Nick Tchayka</dc:creator>
      <pubDate>Sun, 02 Mar 2025 12:38:32 +0000</pubDate>
      <link>https://dev.to/neohaskell/hypersigilating-neohaskell-and-speedrunning-life-4b30</link>
      <guid>https://dev.to/neohaskell/hypersigilating-neohaskell-and-speedrunning-life-4b30</guid>
      <description>&lt;p&gt;Well, all right. So you might be asking where the hell has been Nick? What the hell has been he doing with NeoHaskell and all that jazz. So basically a lot of stuff was happening in my life.&lt;/p&gt;

&lt;p&gt;Some of you might have known that I got married in December. Yay for me. And also throughout that process, I decided to quit my job and basically start rethinking my life. So there was a lot of stuff going on. We prepared a wedding in a month and a half together with my wife. We like to say that it was "Wedding Speedrun Any%," but it was 100% what we really wanted it to be. We had an extremely good time with our closest friends and family and did it as nerdy as we wanted our wedding to be. Basically, we are super happy for that. It was time after being 13 years together.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F03lr70t6lycymzq6r1m3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F03lr70t6lycymzq6r1m3.png" alt="wedding" width="800" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, after that, we also improvised a honeymoon because we hadn't thought about it until two days before the wedding. And we decided to go to Russia. Yes, I know times are weird about that. Some people might like it, some people might not. But to be honest, taking the political views apart, I highlight the fact I don't subscribe to any kind of violence. The country is very beautiful, and especially having relatives there, it was very easy for us to go there and visit. We really, really enjoyed the hospitality of Russian people, taking into account that it was my wife's first time going to that country and my first time going to that country as an adult. So we spent a great time there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ug91cppfanu5abwy4jj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ug91cppfanu5abwy4jj.png" alt="russia" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Meanwhile, I was unemployed, doing a lot of stuff. I really appreciated having free time to be able to do things related to the wedding, the honeymoon, and especially taking care of my home. I took the time to set up a proper home office, clean stuff, sort things around, and essentially get back the balance there. I also reconnected with friends, reconnected with video games, which was something that I had abandoned for a long, long time and that I really enjoy, to be honest. I also reconnected with hobbies like music production, just having fun and reconnecting with life.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fafybluhlnk2l15r634ja.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fafybluhlnk2l15r634ja.png" alt="event model" width="800" height="687"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In February, I was lucky enough to get an offer for a new job, and I accepted. I've been working there for a month already, and it has been a very exciting journey. Of course, it's a new job, new technologies for me, a new business domain, and especially a new kind of workflow—how the teams are organized, how the knowledge is structured, how the codebase is structured, and how a fully product-focused team compares to a services team that I was previously working with. So it has been a lot of learning, of course, a lot of taxing in terms of energy. And yeah, I've been learning for months, and I keep learning.&lt;/p&gt;

&lt;p&gt;But of course, I haven't forgotten about my biggest project, which is NeoHaskell. I really plan to keep going on with that. I really want to continue working on it. Some people have doubts about it, and that’s completely fine. I would be in the same place. There's a lot of discontent in the Elm community due to the opacity of the development process there. Thankfully, NeoHaskell is in a very, very early stage, so there’s no one waiting for production fixes or anything. But whatever.&lt;/p&gt;

&lt;p&gt;Basically, I was also rethinking a bit about how I was working throughout the project. Initially, I had this plan of drawing everything, planning everything first, and then starting to develop. But again, that wasn’t very realistic because there's a lot of stuff to plan and a lot of stuff to develop. So I ended up diving in and just starting to develop. But again, that becomes another rabbit hole because you end up implementing a lot of stuff that you don’t need immediately.&lt;/p&gt;

&lt;p&gt;Given that NeoHaskell is going to have a strong focus on event modeling and event sourcing, I decided that I should probably start planning graphically. For example, the Neo CLI tool will be the first NeoHaskell application. I decided to start with the event model. In fact, you can see here attached the preliminary Neo CLI Event Model. It’s not even finished yet, nor will it ever be, because event models are constantly changing. I want to figure out the best place to put this online so it stays updated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fchlylwrjog1z8btb5khi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fchlylwrjog1z8btb5khi.png" alt="meme" width="800" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You’ll see that there’s a lot of stuff missing there—stuff like slices, chapters, etc. And if you’re not familiar with event modeling, it’s a very great concept. I really recommend reading through Understanding Event Sourcing book. Even if you’re not using event sourcing, event modeling is a great design process to help you simplify how you document and design your software. Of course, feel free to leave your opinions here in the comments or in the Discord channel. I’ll be very happy to discuss this.&lt;/p&gt;

&lt;p&gt;Back again to the topic, I essentially want to take the time to design the minimal stuff, make it using diagrams and graphical resources, and then map those to actual tasks that can be finished in one day. One day doesn’t mean eight hours because I’m not working on this full-time, but one day means a couple of hours that I have in the evening. This will not only enable me to go faster and provide results for the community, but also I believe that it will allow people to onboard faster. This event modeling tool or design process allows us to go much, much faster in terms of onboarding because all the knowledge is right there.&lt;/p&gt;

&lt;p&gt;Writing design documents is hard, but writing diagrams, which are very graphical, is not only easier in my opinion but also much more fun. So basically, I have a branch called develop that has been long-running for a couple of months now. I really want to release the first neo build feature so people can use it, but that’s probably unrealistic. I’ll just end up merging that into the main branch, where the neo build command is basically a Hello World. I think that makes much more sense because then we can keep iterating quickly and providing more stuff there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0fc9ynghzth5qdv7cg2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0fc9ynghzth5qdv7cg2.png" alt="meme" width="720" height="537"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, you might be wondering, but not everything can be done through an event model. And you’re completely right. There’s a lot of stuff that we still need to model and document. For example, one of the things that I have in mind is to create a diagram, a table, or some graphical resource that maps the collection type, class, or trait (which we don’t have right now) to the different type classes that Haskell has. So we would have this trait called collection that we could use in order to make our code more generic without having to get into concepts like Functor, Foldable, etc., which are very useful on their own but do not give immediate value to newcomers.&lt;/p&gt;

&lt;p&gt;So yeah, basically, this is me rambling a little bit about what has been going on, what has been on my mind, and also what I see for the future. I hope this gets you a little bit excited because I really am. I want to keep going forward with the project, and I want to keep hearing from you folks. So thank you for reading this.&lt;/p&gt;

&lt;p&gt;That’s all from my side. The wizard has spoken.&lt;/p&gt;

</description>
      <category>news</category>
      <category>opensource</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>NeoHaskell v0.5.0 - HTTP, TOML, Nested Actions Now Executed and Major Refactoring</title>
      <dc:creator>Nick Tchayka</dc:creator>
      <pubDate>Mon, 16 Sep 2024 15:55:00 +0000</pubDate>
      <link>https://dev.to/neohaskell/neohaskell-v050-http-toml-nested-actions-now-executed-and-major-refactoring-4cb6</link>
      <guid>https://dev.to/neohaskell/neohaskell-v050-http-toml-nested-actions-now-executed-and-major-refactoring-4cb6</guid>
      <description>&lt;p&gt;We are excited to announce the release of &lt;strong&gt;NeoHaskell v0.5.0&lt;/strong&gt;, featuring significant improvements, bug fixes, and new functionalities. This version addresses major issues from previous releases and introduces enhancements that improve the reliability and performance of NeoHaskell applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 New Features and Improvements
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🛠️ Fixed Execution of Nested Actions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Issue Addressed&lt;/strong&gt;: Nested actions were not being executed, leading to incomplete workflows and unexpected behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Refactored the action processing system to correctly handle and execute nested actions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Impact&lt;/strong&gt;: Ensures that all intended actions are performed, providing more reliable and predictable application behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🌐 Introduced HTTP Client Support
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Capability&lt;/strong&gt;: Added HTTP client functionalities using the &lt;code&gt;http-conduit&lt;/code&gt; library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modules Added&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;core/http/Http.hs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;core/http/Http/Client.hs&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Features&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Perform HTTP GET requests with JSON parsing.&lt;/li&gt;
&lt;li&gt;Seamless integration of HTTP requests into NeoHaskell applications.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Note&lt;/strong&gt;: Currently supports only GET requests.&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  📄 Transitioned from YAML to TOML for Configuration
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Change&lt;/strong&gt;: Replaced YAML configuration support with TOML.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reason&lt;/strong&gt;: TOML offers a simpler syntax and is better suited for configuration needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action Required&lt;/strong&gt;: Users must migrate their YAML configuration files to TOML format.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modules Affected&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Removed: &lt;code&gt;core/yaml/Yaml.hs&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Added: &lt;code&gt;core/toml/Toml.hs&lt;/code&gt; (using the &lt;code&gt;toml-parser&lt;/code&gt; library)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  ⚙️ Refactored Core Modules
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Standardization and Cleanup&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Removed custom implementations and redundant GHC extensions.&lt;/li&gt;
&lt;li&gt;Cleaned up imports and exports in core modules for clarity and maintainability.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;IO Module Enhancements&lt;/strong&gt; (&lt;code&gt;core/core/IO.hs&lt;/code&gt;):

&lt;ul&gt;
&lt;li&gt;Added &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;try&lt;/code&gt; functions for improved error handling and functional composition.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Result Module Enhancements&lt;/strong&gt; (&lt;code&gt;core/core/Result.hs&lt;/code&gt;):

&lt;ul&gt;
&lt;li&gt;Introduced &lt;code&gt;fromEither&lt;/code&gt; function for better interoperability with Haskell's &lt;code&gt;Either&lt;/code&gt; type.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  🚀 Improved Service Layer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Action Processing&lt;/strong&gt; (&lt;code&gt;core/service/Action.hs&lt;/code&gt;):

&lt;ul&gt;
&lt;li&gt;Rewrote action processing logic to correctly handle nested actions.&lt;/li&gt;
&lt;li&gt;Adjusted the &lt;code&gt;Action&lt;/code&gt; type and related functions to support new data structures.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Event Handling&lt;/strong&gt; (&lt;code&gt;core/service/Service/EventWorker.hs&lt;/code&gt;):

&lt;ul&gt;
&lt;li&gt;Enhanced event worker logic to accurately process events derived from actions.&lt;/li&gt;
&lt;li&gt;Ensured proper propagation of events throughout the system.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Runtime State Management&lt;/strong&gt; (&lt;code&gt;core/service/Service/RuntimeState.hs&lt;/code&gt;):

&lt;ul&gt;
&lt;li&gt;Refactored runtime state handling to use standard data types.&lt;/li&gt;
&lt;li&gt;Simplified registration of default action handlers and improved extensibility.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  🧹 Removed &lt;code&gt;large-anon&lt;/code&gt; Library and Anonymous Records
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Change&lt;/strong&gt;: Eliminated the &lt;code&gt;large-anon&lt;/code&gt; library and the use of anonymous records.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reason&lt;/strong&gt;: To simplify the codebase, reduce complexity, and improve performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Changes Made&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Replaced anonymous records with standard Haskell data types using &lt;code&gt;data&lt;/code&gt; declarations.&lt;/li&gt;
&lt;li&gt;Removed GHC extensions: &lt;code&gt;OverloadedRecordUpdate&lt;/code&gt;, &lt;code&gt;RebindableSyntax&lt;/code&gt;, and unnecessary &lt;code&gt;OverloadedRecordDot&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Updated all modules to use conventional records, enhancing compatibility and maintainability.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Note&lt;/strong&gt;: This feature might be reintroduced in the future.&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  📝 Miscellaneous Changes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Updated Cabal Files&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cli/nhcli.cabal&lt;/code&gt; and &lt;code&gt;core/nhcore.cabal&lt;/code&gt; updated.&lt;/li&gt;
&lt;li&gt;Removed unused dependencies and GHC extensions.&lt;/li&gt;
&lt;li&gt;Added new dependencies: &lt;code&gt;http-conduit&lt;/code&gt;, &lt;code&gt;toml-parser&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Console and Logging Enhancements&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Improved logging messages for better debugging and visibility.&lt;/li&gt;
&lt;li&gt;Standardized log formats and included more contextual information.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Code Cleanup&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Removed deprecated code and modules (e.g., &lt;code&gt;core/yaml/Yaml.hs&lt;/code&gt;, &lt;code&gt;cli/src/Neo/Transpile.hs&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Ensured all modules are updated to use new data type definitions.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Removed Modules&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Deleted content of &lt;code&gt;core/core/Record.hs&lt;/code&gt; as it's no longer necessary.&lt;/li&gt;
&lt;li&gt;Removed dependencies on external libraries in &lt;code&gt;core/service/Html.hs&lt;/code&gt;, provided placeholders instead.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  ⚠️ Breaking Changes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data Types&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Replaced anonymous records with standard data types.&lt;/li&gt;
&lt;li&gt;Affects the structure of &lt;code&gt;State&lt;/code&gt;, &lt;code&gt;Event&lt;/code&gt;, &lt;code&gt;Action&lt;/code&gt;, and other core components.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;GHC Extensions&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Removed extensions that were previously required for anonymous records.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Configuration Files&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Users need to migrate their configuration files from YAML to TOML format.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Module Imports&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Updated module imports and exports.&lt;/li&gt;
&lt;li&gt;User code may require updates to accommodate these changes.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  🔧 Action Required for Users
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Update Configuration&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Migrate your YAML configuration files to TOML format to align with the new configuration system.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Code Adjustments&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Review your code for dependencies on anonymous records and update to use standard data types.&lt;/li&gt;
&lt;li&gt;Check for any GHC extensions that may no longer be necessary or supported.&lt;/li&gt;
&lt;li&gt;Update module imports to match the new module structure.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  📣 Conclusion
&lt;/h2&gt;

&lt;p&gt;NeoHaskell v0.5.0 brings important fixes and enhancements that improve the overall stability and functionality of the platform. While some changes are breaking, they pave the way for a more robust and maintainable codebase. We recommend all users upgrade to this version and adjust their code accordingly to benefit from the improvements.&lt;/p&gt;

&lt;p&gt;Thank you for your continued support and contributions to NeoHaskell!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>NeoHaskell v0.4.0: Update with Concurrency Fixes and Architectural Improvements</title>
      <dc:creator>Nick Tchayka</dc:creator>
      <pubDate>Sun, 01 Sep 2024 17:33:00 +0000</pubDate>
      <link>https://dev.to/neohaskell/neohaskell-v040-update-with-concurrency-fixes-and-architectural-improvements-267b</link>
      <guid>https://dev.to/neohaskell/neohaskell-v040-update-with-concurrency-fixes-and-architectural-improvements-267b</guid>
      <description>&lt;p&gt;After 3 weeks facing a wall of awful, I managed to fix this concurrency bug in the service worker architecture, where even though the user app loop was being executed properly, the exceptions weren't exiting the app. This critical fix, along with several other significant improvements, marks the release of NeoHaskell v0.4.0. Let's dive into the details of what's new and what's been fixed in this major update.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Concurrency Bug: A Deep Dive
&lt;/h2&gt;

&lt;p&gt;The core of the problem lay in our service worker architecture. While the main application loop was running as expected, any exceptions that occurred weren't properly propagated to cause the application to exit. This led to situations where the app would appear to be running, but was actually in a broken state.&lt;/p&gt;

&lt;p&gt;The fix involved several steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Implementing a &lt;code&gt;shouldExit&lt;/code&gt; flag in the &lt;code&gt;RuntimeState&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;   &lt;span class="kr"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;RuntimeState&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
     &lt;span class="kt"&gt;Record&lt;/span&gt;
       &lt;span class="n"&gt;'&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s"&gt;"actionHandlers"&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;Action&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;HandlerRegistry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s"&gt;"actionsQueue"&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;Channel&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Action&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="s"&gt;"shouldExit"&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Adding exception handlers to each worker thread that set this flag:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;   &lt;span class="kr"&gt;let&lt;/span&gt; &lt;span class="n"&gt;cleanup&lt;/span&gt; &lt;span class="n"&gt;threadName&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
         &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;[init] EXCEPTION: {toText exception}&lt;span class="o"&gt;|]&lt;/span&gt;
         &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;[init] {threadName} cleanup&lt;span class="o"&gt;|]&lt;/span&gt;
         &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="s"&gt;"[init] Cleaning up"&lt;/span&gt;
         &lt;span class="n"&gt;runtimeState&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;RuntimeState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;modify&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;shouldExit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;True&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Modifying each worker to check this flag and exit cleanly when set:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;   &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="kt"&gt;RuntimeState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;runtimeState&lt;/span&gt;
   &lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shouldExit&lt;/span&gt;
     &lt;span class="kr"&gt;then&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
       &lt;span class="n"&gt;print&lt;/span&gt; &lt;span class="s"&gt;"Exiting due to shouldExit flag"&lt;/span&gt;
       &lt;span class="kt"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exitSuccess&lt;/span&gt;
     &lt;span class="kr"&gt;else&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
       &lt;span class="c1"&gt;-- Continue with normal operation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This change ensures that when an exception occurs in any part of the application, all threads are notified and can shut down gracefully, allowing the application to exit properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Major Architectural Improvements
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Service Architecture Refactoring
&lt;/h3&gt;

&lt;p&gt;In this major update, we've completely overhauled the &lt;code&gt;Service&lt;/code&gt; module, splitting it into smaller, more focused modules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Service.Core&lt;/code&gt;: Core types and interfaces&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Service.ActionWorker&lt;/code&gt;: Action processing&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Service.EventWorker&lt;/code&gt;: Event handling and model updates&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Service.RenderWorker&lt;/code&gt;: View rendering&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Service.RuntimeState&lt;/code&gt;: Shared runtime state management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This significant refactoring improves code maintainability and makes the system easier to understand and modify, setting a new foundation for future development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Service Architecture Overview
&lt;/h2&gt;

&lt;p&gt;As part of our architectural improvements, we've refined the core structure of the NeoHaskell Service. To better illustrate these changes, let's examine a high-level diagram of the Service architecture:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi8ywb36fnqe8m4q71h81.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi8ywb36fnqe8m4q71h81.png" alt="architecture diagram" width="662" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ActionsQueue&lt;/strong&gt; and &lt;strong&gt;EventsQueue&lt;/strong&gt;: These channels facilitate communication between different parts of the system. The ActionsQueue handles incoming actions, while the EventsQueue manages events.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;StateRef&lt;/strong&gt;: This is a concurrent variable that holds the current state of the application model.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Workers&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ActionWorker&lt;/strong&gt;: Processes actions from the ActionsQueue and can generate events.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RenderWorker&lt;/strong&gt;: Handles rendering the current state of the application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EventWorker&lt;/strong&gt;: Processes events, updates the model, and can generate new actions.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;init&lt;/strong&gt;, &lt;strong&gt;view&lt;/strong&gt;, &lt;strong&gt;update&lt;/strong&gt; (UserApp): Represents the user's application logic, which initializes the State and ActionsQueue, as well as rendering the state, and updating the state based on the events.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Triggers&lt;/strong&gt;: External sources that can generate events and feed them into the EventsQueue.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The interactions between these components form the core of the NeoHaskell Service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The UserApp initializes the StateRef and ActionsQueue.&lt;/li&gt;
&lt;li&gt;Triggers feed events into the EventsQueue.&lt;/li&gt;
&lt;li&gt;The ActionWorker reads from ActionsQueue and writes to EventsQueue.&lt;/li&gt;
&lt;li&gt;The EventWorker reads from EventsQueue, updates ModelRef, and can write to ActionsQueue.&lt;/li&gt;
&lt;li&gt;The RenderWorker reads from StateRef to render the current state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This architecture provides a clear separation of concerns, allowing for better management of state, actions, and events in NeoHaskell applications. It forms the foundation for the concurrency improvements and bug fixes implemented in this release.&lt;/p&gt;

&lt;p&gt;By clearly defining the roles and interactions of each component, we've created a more robust and maintainable system. This structure allows for easier debugging, better performance, and more predictable behavior in complex applications.&lt;/p&gt;

&lt;p&gt;The refinements in this architecture have directly contributed to resolving the concurrency issues mentioned earlier. By clearly defining the flow of data and the responsibilities of each worker, we've minimized the chances of deadlocks and race conditions, resulting in a more stable and reliable system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enhanced CLI Argument Parsing
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;OptionsParser&lt;/code&gt; module has been renamed to &lt;code&gt;Command&lt;/code&gt; and substantially expanded with new capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Support for parsing &lt;code&gt;Path&lt;/code&gt; type arguments&lt;/li&gt;
&lt;li&gt;Closer integration with the action system for seamless command handling&lt;/li&gt;
&lt;li&gt;Improved error handling and user feedback&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Other Key Improvements
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Terminal Rendering Bug Fix
&lt;/h3&gt;

&lt;p&gt;We resolved a critical issue where the terminal was left in an unusable state after the program exited. This was fixed by properly implementing &lt;code&gt;Vty.shutdown&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;
  &lt;span class="kt"&gt;Brick&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customMainWithDefaultVty&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Just&lt;/span&gt; &lt;span class="n"&gt;eventChannel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;brickApp&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;
&lt;span class="kt"&gt;Vty&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shutdown&lt;/span&gt; &lt;span class="n"&gt;vty&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Additional Improvements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A new &lt;code&gt;ActionResult&lt;/code&gt; type in the &lt;code&gt;Action&lt;/code&gt; module for more robust error handling&lt;/li&gt;
&lt;li&gt;Introduction of the &lt;code&gt;fmt&lt;/code&gt; quasi-quoter for text interpolation&lt;/li&gt;
&lt;li&gt;New utility functions added to core modules like &lt;code&gt;Array&lt;/code&gt;, &lt;code&gt;Basics&lt;/code&gt;, and &lt;code&gt;IO&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;NeoHaskell v0.4.0 represents a significant step forward in the project's development. The concurrency bug fix addresses a critical issue in the system, while the architectural improvements set the stage for more robust and maintainable code in the future.&lt;/p&gt;

&lt;p&gt;These updates provide a stronger foundation for NeoHaskell applications and demonstrate our commitment to improving the language.&lt;/p&gt;

&lt;p&gt;As we move forward, we welcome feedback and contributions from the community to help shape the future of NeoHaskell. This major release marks an important milestone, but our work continues as we strive to make NeoHaskell an even more powerful and user-friendly language.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>opensource</category>
      <category>cli</category>
      <category>haskell</category>
    </item>
    <item>
      <title>Understanding Triggers in NeoHaskell: A Gateway to Event-Driven Programming</title>
      <dc:creator>Nick Tchayka</dc:creator>
      <pubDate>Mon, 05 Aug 2024 13:02:00 +0000</pubDate>
      <link>https://dev.to/neohaskell/understanding-triggers-in-neohaskell-a-gateway-to-event-driven-programming-49nb</link>
      <guid>https://dev.to/neohaskell/understanding-triggers-in-neohaskell-a-gateway-to-event-driven-programming-49nb</guid>
      <description>&lt;p&gt;Since the release of NeoHaskell v0.3.0, we've noticed some confusion about what Triggers are and how they can be useful in real-world applications. In this post, we'll dive deeper into the concept of Triggers and explore their potential in various scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Triggers?
&lt;/h2&gt;

&lt;p&gt;At their core, Triggers in NeoHaskell are entry points to your application where external agents can generate events in your service. They act as a bridge between the outside world and your application's event loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Simplest Trigger: Time
&lt;/h2&gt;

&lt;p&gt;Let's start with the simplest example we provided in our release notes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;tickTrigger&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Trigger&lt;/span&gt; &lt;span class="kt"&gt;TickEvent&lt;/span&gt;
&lt;span class="n"&gt;tickTrigger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;triggerEveryMilliseconds&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Tick&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This Trigger generates a &lt;code&gt;Tick&lt;/code&gt; event in your application every 1000 milliseconds. While simple, it demonstrates the key concept: an external factor (in this case, the passage of time) is causing events to occur in your application.&lt;/p&gt;

&lt;p&gt;Let's take a look at hypothetical triggers that could be implemented (they do not exist at the time of writing this, but they will be probably implemented in future versions).&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond Time: HTTP Servers
&lt;/h2&gt;

&lt;p&gt;Triggers are far more powerful than just timers. Let's look at how they could be used to create an HTTP server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;postFooTrigger&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Trigger&lt;/span&gt; &lt;span class="kt"&gt;MyEvent&lt;/span&gt;
&lt;span class="n"&gt;postFooTrigger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trigger&lt;/span&gt; &lt;span class="kt"&gt;ANON&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/foo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;MyEvent&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we're creating a Trigger that listens for POST requests to the "/foo" endpoint. Whenever a request is received, it generates a &lt;code&gt;MyEvent&lt;/code&gt; in your application. This is how Triggers facilitate building HTTP servers: they provide a way for incoming HTTP requests to generate events in your application's event loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  More Real-World Examples
&lt;/h2&gt;

&lt;p&gt;Triggers aren't limited to just time and HTTP. Here are a few more examples to illustrate their versatility:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Chat Bot&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;   &lt;span class="n"&gt;discordMessageTrigger&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Trigger&lt;/span&gt; &lt;span class="kt"&gt;ChatEvent&lt;/span&gt;
   &lt;span class="n"&gt;discordMessageTrigger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Discord&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onMessage&lt;/span&gt; &lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; 
     &lt;span class="kt"&gt;NewMessage&lt;/span&gt; &lt;span class="kt"&gt;ANON&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;author&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This Trigger would generate a &lt;code&gt;NewMessage&lt;/code&gt; event every time a message is received in a Discord channel.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;File System Watcher&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;   &lt;span class="n"&gt;fileChangeTrigger&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Trigger&lt;/span&gt; &lt;span class="kt"&gt;FileEvent&lt;/span&gt;
   &lt;span class="n"&gt;fileChangeTrigger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;FileSystem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onChange&lt;/span&gt; &lt;span class="s"&gt;"/path/to/watch"&lt;/span&gt; &lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;change&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
     &lt;span class="kt"&gt;FileChanged&lt;/span&gt; &lt;span class="kt"&gt;ANON&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;change&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;change&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;type&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This Trigger would generate a &lt;code&gt;FileChanged&lt;/code&gt; event whenever files in the specified directory are modified.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Database Listener&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;   &lt;span class="n"&gt;dbChangeTrigger&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Trigger&lt;/span&gt; &lt;span class="kt"&gt;DBEvent&lt;/span&gt;
   &lt;span class="n"&gt;dbChangeTrigger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Database&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onUpdate&lt;/span&gt; &lt;span class="s"&gt;"users"&lt;/span&gt; &lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
     &lt;span class="kt"&gt;UserUpdated&lt;/span&gt; &lt;span class="kt"&gt;ANON&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;changedFields&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This Trigger would generate a &lt;code&gt;UserUpdated&lt;/code&gt; event whenever a record in the "users" table is updated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Triggers Matter
&lt;/h2&gt;

&lt;p&gt;Triggers are crucial because they allow your NeoHaskell application to react to the outside world in a structured, functional manner. They provide a clean separation between:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How external events are received (the Trigger)&lt;/li&gt;
&lt;li&gt;How those events are represented in your application (the Event)&lt;/li&gt;
&lt;li&gt;How your application responds to those events (the Update function)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This separation makes it easier to reason about your application's behavior, test individual components, and modify or extend functionality over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Triggers in NeoHaskell are a powerful abstraction that enable truly event-driven programming. Whether you're building a simple CLI tool with a timer, a web server handling HTTP requests, a chat bot responding to messages, or a complex system reacting to database changes and file system events, Triggers provide a consistent, functional approach to handling external inputs.&lt;/p&gt;

&lt;p&gt;We're excited to see what the NeoHaskell community builds with Triggers. If you have any questions or want to share what you're working on, join us on Discord or GitHub. Happy coding!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>opensource</category>
      <category>beginners</category>
      <category>haskell</category>
    </item>
    <item>
      <title>Introducing NeoHaskell v0.3.0: Triggers, Actions, and Services</title>
      <dc:creator>Nick Tchayka</dc:creator>
      <pubDate>Sun, 04 Aug 2024 17:37:00 +0000</pubDate>
      <link>https://dev.to/neohaskell/introducing-neohaskell-v030-triggers-actions-and-services-2ae</link>
      <guid>https://dev.to/neohaskell/introducing-neohaskell-v030-triggers-actions-and-services-2ae</guid>
      <description>&lt;p&gt;We're thrilled to announce the release of NeoHaskell v0.3.0! This version brings significant enhancements to our event-driven architecture, making it even more powerful and flexible. The key improvements in this release focus on the introduction of triggers, renaming of core concepts for clarity, and further refinements.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Commands to Actions: A Clearer Mental Model
&lt;/h2&gt;

&lt;p&gt;In our ongoing effort to make NeoHaskell more intuitive, we've renamed the &lt;code&gt;Command&lt;/code&gt; concept to &lt;code&gt;Action&lt;/code&gt;. This change better reflects the nature of these operations as side effects that can be tracked and managed within our architecture. &lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Triggers: Unlocking a World of Possibilities
&lt;/h2&gt;

&lt;p&gt;The introduction of triggers in v0.3.0 is a game-changer for NeoHaskell applications. Triggers provide a powerful and flexible way to handle asynchronous events and background processes, opening up a vast array of possibilities for your projects.&lt;/p&gt;

&lt;p&gt;Let's start with a simple example - a time-based trigger:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="n"&gt;tickTrigger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="kt"&gt;Time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;triggerEveryMilliseconds&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Tick&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This minimal trigger fires a &lt;code&gt;Tick&lt;/code&gt; event every 1000 milliseconds. But don't let its simplicity fool you - this is just the tip of the iceberg!&lt;/p&gt;

&lt;p&gt;With the trigger system in place, NeoHaskell is now poised to support a wide range of exciting applications:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;HTTP Servers&lt;/strong&gt;: Imagine creating triggers that respond to incoming HTTP requests, allowing you to build full-fledged web applications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Chat Bots&lt;/strong&gt;: Whether it's Discord, Telegram, or Slack, you could create triggers that listen for and respond to chat messages in real-time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;IoT Applications&lt;/strong&gt;: Set up triggers to handle data streams from IoT devices, enabling you to build sophisticated monitoring and control systems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Database Listeners&lt;/strong&gt;: Create triggers that react to database changes, perfect for building reactive data processing pipelines.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;File System Watchers&lt;/strong&gt;: Monitor file system events and trigger actions when files are created, modified, or deleted.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The possibilities are virtually endless. Whether you're building a simple CLI tool or a complex distributed system, triggers provide the foundation for handling real-world events in a clean, functional manner.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Platform to Service: A More Focused Runtime
&lt;/h2&gt;

&lt;p&gt;We've refined our core runtime concept, renaming &lt;code&gt;Platform&lt;/code&gt; to &lt;code&gt;Service&lt;/code&gt;. This change reflects a more focused approach to managing your application's lifecycle and event handling. &lt;code&gt;Service&lt;/code&gt; is a much narrower concept that is much better understood by everyone. And it also opens up the possibility of executing multiple of those in a single application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Involved
&lt;/h2&gt;

&lt;p&gt;We're excited to see what the community builds with NeoHaskell v0.3.0! Here's how you can get started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check out our GitHub repository for the latest code&lt;/li&gt;
&lt;li&gt;Join our Discord community to discuss ideas and get help&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your feedback and contributions are crucial as we continue to evolve NeoHaskell. Let's work together to create a more accessible and powerful development experience!&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;Nick&lt;/p&gt;

</description>
      <category>programming</category>
      <category>opensource</category>
      <category>cli</category>
      <category>haskell</category>
    </item>
    <item>
      <title>Announcing NeoHaskell v0.2.0: Bringing Elm-Inspired Architecture to CLI Apps</title>
      <dc:creator>Nick Tchayka</dc:creator>
      <pubDate>Sat, 27 Jul 2024 10:38:00 +0000</pubDate>
      <link>https://dev.to/neohaskell/announcing-neohaskell-v020-bringing-elm-inspired-architecture-to-cli-apps-54db</link>
      <guid>https://dev.to/neohaskell/announcing-neohaskell-v020-bringing-elm-inspired-architecture-to-cli-apps-54db</guid>
      <description>&lt;p&gt;We're excited to announce the release of NeoHaskell v0.2.0! This version marks a significant milestone in our journey to create a more accessible and powerful Haskell-based language. With this release, we're introducing a basic scaffolding for CLI applications inspired by Elm's architecture, along with substantial enhancements to our core library.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Elm-Inspired CLI Architecture
&lt;/h2&gt;

&lt;p&gt;One of the most exciting features in v0.2.0 is the introduction of, an Elm-inspired, event sourcing architecture for building CLI applications. This approach brings the clarity and maintainability of Elm's design to the world of command-line tools.&lt;/p&gt;

&lt;p&gt;This architecture allows developers to create CLI apps with a clear separation of concerns, making it easier to reason about application state and user interactions.&lt;/p&gt;

&lt;p&gt;Let's look at an example of how to build a simple CLI app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;SimpleTodo&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;where&lt;/span&gt;

&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Core&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Command&lt;/span&gt; &lt;span class="n"&gt;qualified&lt;/span&gt;
&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Platform&lt;/span&gt; &lt;span class="n"&gt;qualified&lt;/span&gt;

&lt;span class="kr"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="kt"&gt;Record&lt;/span&gt;
    &lt;span class="n"&gt;'&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s"&gt;"todos"&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;Array&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="s"&gt;"currentInput"&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
     &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;Message&lt;/span&gt;
  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;AddTodo&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;UpdateInput&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;RemoveTodo&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;NoOp&lt;/span&gt;
  &lt;span class="kr"&gt;deriving&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Show&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt; &lt;span class="kt"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="kr"&gt;let&lt;/span&gt; &lt;span class="n"&gt;initialModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="kt"&gt;ANON&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;currentInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kr"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;none&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Message&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt; &lt;span class="kt"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;
    &lt;span class="kt"&gt;AddTodo&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isEmpty&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentInput&lt;/span&gt;
        &lt;span class="kr"&gt;then&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;none&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kr"&gt;else&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentInput&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;currentInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
              &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="kt"&gt;Command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;none&lt;/span&gt;
          &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kt"&gt;UpdateInput&lt;/span&gt; &lt;span class="n"&gt;newInput&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;currentInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newInput&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;none&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kt"&gt;RemoveTodo&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;removeAt&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="kt"&gt;Command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;none&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kt"&gt;NoOp&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;none&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
&lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
  &lt;span class="kr"&gt;let&lt;/span&gt; &lt;span class="n"&gt;todoList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;joinWith&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;todos&lt;/span&gt;
  &lt;span class="kr"&gt;let&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Todo List:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
  &lt;span class="kr"&gt;let&lt;/span&gt; &lt;span class="n"&gt;footer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Current input: "&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentInput&lt;/span&gt;
  &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;todoList&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;footer&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;IO&lt;/span&gt; &lt;span class="nb"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Platform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ANON&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example demonstrates the key components of the Elm-inspired architecture:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;Model&lt;/code&gt;: Represents the application state&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Message&lt;/code&gt;: Defines the possible events in the application&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;init&lt;/code&gt;: Sets up the initial model and commands&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;update&lt;/code&gt;: Handles state transitions based on messages&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;view&lt;/code&gt;: Renders the current state as text&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;main&lt;/code&gt;: Initializes the application using the &lt;code&gt;Platform&lt;/code&gt; module&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Expanded Core Library
&lt;/h2&gt;

&lt;p&gt;We've significantly enhanced our core library to provide more powerful tools for NeoHaskell developers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New concurrency primitives: &lt;code&gt;Channel&lt;/code&gt;, &lt;code&gt;Var&lt;/code&gt;, and &lt;code&gt;ConcurrentVar&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AsyncIO&lt;/code&gt; module for handling asynchronous operations&lt;/li&gt;
&lt;li&gt;Extended &lt;code&gt;Array&lt;/code&gt; module with useful functions like &lt;code&gt;flatMap&lt;/code&gt; and &lt;code&gt;forEach&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Version&lt;/code&gt; module for parsing and working with semantic versions&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Unknown&lt;/code&gt; type for handling dynamic typing scenarios&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;Record&lt;/code&gt; module for working with extensible records&lt;/li&gt;
&lt;li&gt;New &lt;code&gt;Json&lt;/code&gt; and &lt;code&gt;Yaml&lt;/code&gt; modules for data serialization&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;OptionsParser&lt;/code&gt; module to simplify CLI argument parsing&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;Console&lt;/code&gt; module with built-in debugging capabilities&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Trait System Enhancements
&lt;/h2&gt;

&lt;p&gt;We've reorganized and expanded our trait system to provide a more cohesive and powerful set of abstractions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Improved &lt;code&gt;Appendable&lt;/code&gt;, &lt;code&gt;Applicable&lt;/code&gt;, and &lt;code&gt;Combinable&lt;/code&gt; traits&lt;/li&gt;
&lt;li&gt;A new &lt;code&gt;ToText&lt;/code&gt; trait for consistent string conversion across types&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get Involved
&lt;/h2&gt;

&lt;p&gt;We're excited to see what the community builds with NeoHaskell v0.2.0! Here's how you can get started:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check out our &lt;a href="https://github.com/neohaskell/NeoHaskell" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; for the latest code&lt;/li&gt;
&lt;li&gt;Join our &lt;a href="https://discord.com/invite/wDj3UYzec8" rel="noopener noreferrer"&gt;Discord community&lt;/a&gt; to discuss ideas and get help&lt;/li&gt;
&lt;li&gt;Try building a small CLI app and share your experience&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Your feedback and contributions are crucial as we continue to evolve NeoHaskell. Let's work together to create a more accessible and powerful development experience!&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;Nick&lt;/p&gt;

</description>
      <category>programming</category>
      <category>opensource</category>
      <category>cli</category>
      <category>haskell</category>
    </item>
    <item>
      <title>DevLog 00002 - A main loop working</title>
      <dc:creator>Nick Tchayka</dc:creator>
      <pubDate>Wed, 24 Jul 2024 09:20:00 +0000</pubDate>
      <link>https://dev.to/neohaskell/devlog-00002-a-main-loop-working-31kj</link>
      <guid>https://dev.to/neohaskell/devlog-00002-a-main-loop-working-31kj</guid>
      <description>&lt;p&gt;This week I kept working on having a working Elm-style event-sourcing application main loop in NeoHaskell, and I managed it!&lt;/p&gt;

&lt;p&gt;What does it look like to use this right now? Well, more or less like the following. Let’s say we want to write an app that reads a file and exits. Here’s an extremely contrived example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight haskell"&gt;&lt;code&gt;&lt;span class="kr"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Record&lt;/span&gt;
  &lt;span class="n"&gt;'&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="s"&gt;"content"&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
   &lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;initialModel&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt;
&lt;span class="n"&gt;initialModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ANON&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;Message&lt;/span&gt;
  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ContentRetrieved&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;FailedToRead&lt;/span&gt;

&lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt; &lt;span class="kt"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
  &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;initialModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="kt"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt; &lt;span class="kt"&gt;ANON&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;test.txt&lt;span class="o"&gt;|]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;onSuccess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ContentRetrieved&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;onFailure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;\&lt;/span&gt;&lt;span class="kr"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;FailedToRead&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Message&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt; &lt;span class="kt"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="kr"&gt;case&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="kr"&gt;of&lt;/span&gt;

    &lt;span class="kt"&gt;ContentRetrieved&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; 
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ANON&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;none&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kt"&gt;FailedToRead&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ANON&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ERROR"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kt"&gt;Command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;none&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Html&lt;/span&gt;
&lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &amp;lt;div&amp;gt;{model.content}&amp;lt;/div&amp;gt;
  &lt;span class="o"&gt;|]&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Platform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="kt"&gt;ANON&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don’t get too clinged to the syntax, as it will change in the future. I’m aware that it is not pretty 😄&lt;/p&gt;

&lt;p&gt;If you know a bit of Elm, you might get it straight away, but if you don’t you probably are wondering how all of this works. Either way, you might be thinking that this is overkill for just reading a file and printing it, and you are right!&lt;/p&gt;

&lt;p&gt;If you still have no idea what is happening here, don’t worry, documentation will be on its way once we finalize this first iteration, but to give you a quick hint: This is setting up a loop in the app where the update function gets executed each time an event gets registered in the app, in this case only once when the file gets read (or not). Because no more events happen, the application will end.&lt;/p&gt;

&lt;p&gt;The view function is constantly rendering the model (at 60fps approximately).&lt;/p&gt;

&lt;p&gt;Commands, update, and view, all run on different threads, ensuring that your app doesn’t choke on any of those.&lt;/p&gt;

&lt;p&gt;Next step is to implement subscriptions, to allow doing much more fun stuff, like listening for interactions in the view, or listening for events from external places (like workers written in other programming languages like Python).&lt;/p&gt;

&lt;p&gt;On top of that, tracing functions like print, or trace, are being prepared so they print to a separate thread and output too, which will end up in OpenTelemetry.&lt;/p&gt;

&lt;p&gt;Either way, once I got the minimum things implemented for writing a simple build command I’ll merge this and probably work on a distribution script for everyone to try this :)&lt;/p&gt;

&lt;p&gt;As usual, you’re invited to &lt;a href="https://discord.com/invite/wDj3UYzec8" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; and &lt;a href="https://github.com/neohaskell" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; :D&lt;/p&gt;

</description>
      <category>programming</category>
      <category>opensource</category>
      <category>cli</category>
      <category>haskell</category>
    </item>
    <item>
      <title>DevLog 00001 - Command Line Updates</title>
      <dc:creator>Nick Tchayka</dc:creator>
      <pubDate>Wed, 17 Jul 2024 11:17:00 +0000</pubDate>
      <link>https://dev.to/neohaskell/devlog-00001-command-line-updates-24f3</link>
      <guid>https://dev.to/neohaskell/devlog-00001-command-line-updates-24f3</guid>
      <description>&lt;p&gt;It was a long time since I wrote something decent about NeoHaskell, and my plan was to build openly, so I might start writing devlogs more frequently to publish progress and be able to receive feedback. Many people have sent suggestions about the project and I’m very grateful about them. Also, I think it is cool to have some logs to see how the stuff progresses. It’s easy to dismiss work when one doesn’t write about it.&lt;/p&gt;

&lt;p&gt;Lately I’ve been pushing NeoHaskell to get the minimal necessary functionality to be able to write a command line tool for interacting with NeoHaskell projects. This led me to implement multiple micro features in the project, but also it started shaping some interesting modules in the core library.&lt;/p&gt;

&lt;p&gt;Perhaps one of the greatest finds for the core library was the awesome library &lt;a href="https://github.com/NorfairKing/opt-env-conf" rel="noopener noreferrer"&gt;&lt;code&gt;opt-env-conf&lt;/code&gt;&lt;/a&gt; by &lt;code&gt;NorfairKing&lt;/code&gt; on GitHub. What looks on the surface as just another command line argument parsing library, is actually a masterpiece in developer experience design IMO. This library not only allows you to define parsers for your command line program arguments, but also define requirements in terms of environment variables and configuration files. On top of that, it also lets you generate manpages, and autocompletions for your typical shells like Bash, ZSH, Fish, and others.&lt;/p&gt;

&lt;p&gt;This library alings very well with the NeoHaskell philosophy of “let the tool do as much as possible, freeing the user of repetitive tasks”. I’ve validated the existence of environment variables countless times in many languages and with many different tools in techniques. It is very refreshing to be able to have a library that has this in mind already, and that’s why I’ve chosen it as the underlying technology of the &lt;code&gt;OptionsParser&lt;/code&gt; module in the NeoHaskell core library (name probably will change).&lt;/p&gt;

&lt;p&gt;One of the main patterns in NeoHaskell is the &lt;em&gt;Parse, don’t validate&lt;/em&gt; philosophy. But NeoHaskell tries to take it even further, by allowing the developer to write parsing code once.&lt;/p&gt;

&lt;p&gt;How? Right now it is not fully decided yet, since we have only one parsing module (OptionsParser), but the idea is that you write parsing code once with the parser of your choice (e.g. OptionsParser), and then, if needed, you could switch into a different one (e.g. JSON) with minimal code changes, allowing your app code to evolve slowly into different implementations and platorms.&lt;/p&gt;

&lt;p&gt;Perhaps you start writing a CLI app that’s easy to test, but then you decide that it should be an HTTP server, after a while you decide that it could be a mobile app. Those switches shouldn’t be a whole rewrite of the app, and the parsing code for the types that make the boundaries of your application should stay the same, or at least as similar as possible to the previous iteration.&lt;/p&gt;

&lt;p&gt;The OptionsParser module implements a thin layer over &lt;code&gt;opt-env-conf&lt;/code&gt; to start defining this kind of API, where one can parse different fields by providing a configuration in a record.&lt;/p&gt;

&lt;h2&gt;
  
  
  Records
&lt;/h2&gt;

&lt;p&gt;Another great find that goes straight into the style of NeoHaskell is &lt;code&gt;large-anon&lt;/code&gt;. A Library that allows working with records in a very flexible way.&lt;/p&gt;

&lt;p&gt;Of course, Haskell does have records through the usage of &lt;code&gt;data&lt;/code&gt;, but those aren’t expandable, nor we can match structurally in type signatures easily. And of course, we cannot just make a record on the fly and pass it to a function.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;large-anon&lt;/code&gt; provides fixes to all these problems, and also provides a cool DSL that allows you to write code to build records in an imperative way. Also, they implement JSON serialization out of the box, so you don’t have to write any code to enable it for the records you write.&lt;/p&gt;

&lt;p&gt;In Haskell, these constructs aren’t first class, so in future versions of NeoHaskell, custom syntax will be introduced to work easily with records.&lt;/p&gt;

&lt;h2&gt;
  
  
  Commands: Side effects and interop
&lt;/h2&gt;

&lt;p&gt;By the time I’m writing this, I’m in the middle of implementing commands and command handling.&lt;/p&gt;

&lt;p&gt;Commands in NeoHaskell are very similar to &lt;code&gt;Cmd&lt;/code&gt;s in Elm. It is a value that, if picked by the NeoHaskell runtime, it will execute some kind of side effect.&lt;/p&gt;

&lt;p&gt;There’s an interesting twist in NeoHaskell commands: The command definition and the handling is completely decoupled.&lt;/p&gt;

&lt;p&gt;In fact, not only the handling is done in a separate thread, but you could implement handlers in &lt;strong&gt;any language&lt;/strong&gt;. Yes, you read that right.&lt;/p&gt;

&lt;p&gt;Of course, right now this would be pretty rudimentary, but over the versions I hope that the API stabilizes and one could have a very lightweight library for different languages to implement these command handlers in a very easy way that’s integrated with the rest of the codebase.&lt;/p&gt;

&lt;p&gt;On top of that, commands can be declared &lt;strong&gt;idempotent&lt;/strong&gt;, this means that we say that the command can be repeated without additional effects happening. Think of when you call an elevator and you keep pushing the button, no additional effects happen, the elevator keeps coming.&lt;/p&gt;

&lt;p&gt;This is useful for when the &lt;strong&gt;time travelling debugger&lt;/strong&gt; gets implemented. The idea is that you should be able to debug your app by going forward and backward through the execution of the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Event Sourcing and the Elm architecture
&lt;/h2&gt;

&lt;p&gt;The time travelling thingy would be possible thanks to the fact that the main architecture for NeoHaskell apps is the Elm architecture, which essentially is event sourcing&lt;/p&gt;

&lt;p&gt;If you’re not familiar with either one, think of your bank account. When you go into the ledger of it, you can see the withdrawals and deposits. And thanks to those, you can calculate the balance at any time by looking at those.&lt;/p&gt;

&lt;p&gt;That’s how event sourcing works essentially, you store events and you calculate the state of the app out of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What next?
&lt;/h2&gt;

&lt;p&gt;Once I finish implementing the necessary things to have a hello world app for the terminal using these patterns, I’ll probably start to work on a build command in the neo CLI tool that grabs &lt;code&gt;project.yaml&lt;/code&gt; and builds the project from there.&lt;/p&gt;

&lt;p&gt;I’ve got lots of ideas to come for that, like a nice terminal UI based on &lt;a href="https://github.com/leostera/minttea" rel="noopener noreferrer"&gt;&lt;code&gt;minttea&lt;/code&gt;&lt;/a&gt; by &lt;code&gt;leostera&lt;/code&gt;. Also, implicit imports that are configurable, so you don’t have to import any module if you already have it in your deps, and start implementing custom syntax.&lt;/p&gt;

&lt;p&gt;I’m pretty excited about the project, it’s addictive to code on this codebase heh.&lt;/p&gt;

&lt;p&gt;As always, I invite you to the Discord server to have a chat, and of course to the &lt;a href="https://github.com/neohaskell/neohaskell" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt; to contribute if that’s your thing. See you around!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>opensource</category>
      <category>cli</category>
      <category>haskell</category>
    </item>
    <item>
      <title>Happy Birthday Me, Happy Birthday NeoHaskell</title>
      <dc:creator>Nick Tchayka</dc:creator>
      <pubDate>Sun, 26 May 2024 22:09:00 +0000</pubDate>
      <link>https://dev.to/nickseagull/happy-birthday-me-happy-birthday-neohaskell-2nk5</link>
      <guid>https://dev.to/nickseagull/happy-birthday-me-happy-birthday-neohaskell-2nk5</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj1oif9h3k8i70m1rpmfw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj1oif9h3k8i70m1rpmfw.png" alt="a cyberpunk half-man-half-machine being is looking with a grin at a cake, a sign of a neon happy birthday is behind him" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today is a special day for me—it's my birthday and also the release of the first version of NeoHaskell! 🎉 It's exciting to see it being born into the aethereal currents of the internet 30 years after my own birth.&lt;/p&gt;

&lt;p&gt;On a personal note, I'm feeling much better since &lt;a href="https://dev.to/neohaskell/coming-out-as-an-eldritch-god-1nha"&gt;my last post&lt;/a&gt;. I've been focusing on my well-being, remodeling my apartment, and really listening to what my body needs. This reboot of NeoHaskell aligns perfectly with my renewed energy and excitement for ongoing development.&lt;/p&gt;

&lt;h3&gt;
  
  
  First Version Highlights
&lt;/h3&gt;

&lt;p&gt;This first version comes with a forked version of &lt;code&gt;nri-prelude&lt;/code&gt;, an excellent library by NoRedInk, designed with Elm's philosophy in mind and mimicking the Elm core libraries. NeoHaskell takes this as an inspiring starting point to build upon, providing a solid foundation for future development.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's Inside the Core Library
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Accumulator:&lt;/strong&gt; A DSL to gather values into an accumulable type.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Array:&lt;/strong&gt; Fast immutable arrays.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Basics:&lt;/strong&gt; Fundamental operations and types.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Char:&lt;/strong&gt; Character operations with ASCII and Unicode support.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Console and File:&lt;/strong&gt; Basic IO operations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LinkedList:&lt;/strong&gt; Comprehensive list operations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Map:&lt;/strong&gt; Builder API for maps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maybe:&lt;/strong&gt; Handling optional values.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text:&lt;/strong&gt; Text operations including substring handling and formatting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traits:&lt;/strong&gt; Traits for appendable, default, mappable, and thenable types.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These changes aim to create a well-structured and documented codebase, making it easier for others to contribute and ensuring the project’s scalability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;p&gt;There aren't any detailed guides or tutorials yet, but you can clone the repository at &lt;a href="https://github.com/neohaskell/neohaskell-starter" rel="noopener noreferrer"&gt;NeoHaskell Starter&lt;/a&gt; to start playing with the new version. For any help or instructions, join us on &lt;a href="https://discord.com/invite/wDj3UYzec8" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; where the community is ready to support you.&lt;/p&gt;

&lt;p&gt;Thanks for being a part of this journey. Let's make great things happen with NeoHaskell!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>opensource</category>
      <category>haskell</category>
    </item>
    <item>
      <title>Introducing NeoHaskell: A beacon of joy in a greyed tech world</title>
      <dc:creator>Nick Tchayka</dc:creator>
      <pubDate>Sun, 24 Sep 2023 15:02:07 +0000</pubDate>
      <link>https://dev.to/neohaskell/introducing-neohaskell-a-beacon-of-joy-in-a-greyed-tech-world-4f9b</link>
      <guid>https://dev.to/neohaskell/introducing-neohaskell-a-beacon-of-joy-in-a-greyed-tech-world-4f9b</guid>
      <description>&lt;p&gt;Today, I'm proud to announce a (free and open-source) project that I've been working on for many years:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://neohaskell.org" rel="noopener noreferrer"&gt;NeoHaskell, a dialect of Haskell that prioritizes newcomer-friendliness and productivity.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I embarked on the NeoHaskell project fueled by a diverse array of motivations. &lt;strong&gt;I see Haskell as a supremely potent language&lt;/strong&gt;, leading the frontier of software development due to its inventive and meticulously crafted nature. However, its potential seems overshadowed by intricate details and a community primarily focused on resolving theoretical academic and mathematical challenges, often overlooking pragmatic solutions, which can be overwhelming for newcomers. Based on my experience with incorporating &lt;strong&gt;Haskell into production&lt;/strong&gt; for two years and the subsequent transition to TypeScript due to escalating complexity, after innumerable conversations with my colleagues at &lt;a href="https://www.theagilemonkeys.com/" rel="noopener noreferrer"&gt;The Agile Monkeys&lt;/a&gt;, a critical need for a language that could refine software development while preserving the groundbreaking aspects of Haskell was recognized. This realization, coupled with the challenges encountered in the software development sector, inspired the creation of NeoHaskell. Through this initiative, &lt;strong&gt;I aspire to develop an optimal programming language and ecosystem that eradicates accidental complexity, either in mental form, or in code form.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a language for those who have just too many things in their head and they want to release their ideas, but don't have the time to commit daily to maintain the required context of their projects in their heads. For those who want to play and have fun while producing awesome software, regardless of their experience, background, or interests. And for those teams that, inevitably, are high-rotational (either internally in the company, or externally) but want to be productive and happy while performing their craft.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz10la3egntwr83cejt51.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz10la3egntwr83cejt51.jpeg" alt="A lighthouse beaming upwards a rainbow in a grayscale world" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A language? A dialect? What do you mean?
&lt;/h2&gt;

&lt;p&gt;Depending on who you ask, &lt;strong&gt;a programming language can be different things.&lt;/strong&gt; If you ask the Haskell community, many will tell you that the language is &lt;a href="https://www.haskell.org/definition/haskell2010.pdf" rel="noopener noreferrer"&gt;the Haskell specification&lt;/a&gt;, and that what currently is being used is not Haskell itself, but an extension of Haskell that is supported by the &lt;a href="https://www.haskell.org/ghc/" rel="noopener noreferrer"&gt;GHC compiler&lt;/a&gt;. &lt;a href="https://iso-9899.info/wiki/The_Standard" rel="noopener noreferrer"&gt;Similar to the C language&lt;/a&gt;, &lt;em&gt;a programming language would be a specification.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Other people might tell you that &lt;em&gt;a programming language is the result of the supported features of its compiler&lt;/em&gt;, &lt;a href="https://prev.rust-lang.org/en-US/documentation.html#:~:text=While%20Rust%20does%20not%20have%20a%20specification%2C%20the,detail.%20It%20tends%20to%20be%20out%20of%20date." rel="noopener noreferrer"&gt;like Rust&lt;/a&gt;, which keeps evolving with time.&lt;/p&gt;

&lt;p&gt;I personally think that a programming language is &lt;strong&gt;the result of the agreement of its community on tools, libraries, patterns and practices.&lt;/strong&gt; I hear folks saying "he didn't learn Python, he is programming in Java in Python", which is the affirmation of this.&lt;/p&gt;

&lt;p&gt;NeoHaskell exploits this philosophy to establish &lt;strong&gt;a parallel universe in the Haskell ecosystem&lt;/strong&gt;, piggybacking the extremely good tooling and libraries that are already there, and were there for a long time. It establishes completely different patterns, practices, naming, and even &lt;strong&gt;approaches to code that would be considered heretic in Haskell.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The solution is not having more hands implementing more features, the solution is to stop.&lt;/strong&gt; And prioritize as if this was a product.&lt;/p&gt;

&lt;p&gt;This is not a priority for the Haskell community, and that's the point:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NeoHaskell is not Haskell, it's a parallel universe built on top of it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbrspcn6mcfx47cwifufh.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbrspcn6mcfx47cwifufh.jpeg" alt="a crowd of people celebrating inside of a colorful bubble, in the middle of a grayscale crowd" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's the goal?
&lt;/h2&gt;

&lt;p&gt;NeoHaskell’s core mission is to provide a seamless, productive ecosystem for &lt;strong&gt;joyful software development&lt;/strong&gt;. It’s designed to guide developers toward faster, more reliable releases, through a concentrated effort to &lt;strong&gt;alleviate cognitive load, by removing unnecessary complexity and decision making.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We welcome developers from diverse backgrounds, including backend and frontend development, data analysis, mobile development, game development, and whatever you can image. While simplification of the development process is a priority, NeoHaskell also emphasizes the importance of &lt;strong&gt;improving developer satisfaction by incorporating structured architectures to reduce decision making even more.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;NeoHaskell's vision is to render the development process more user-friendly and enjoyable, enabling users to realize their ideas effortlessly and efficiently. &lt;strong&gt;It wants to transform the development experience, making it feel more like “play” rather than “work.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3to8s779373emjzpfirj.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3to8s779373emjzpfirj.jpeg" alt="a photography a colorful construction worker playing on a swing, a group of construction workers look at him with their arms crossed, everything in grayscale but the construction worker on the swing" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not just documenting Haskell?
&lt;/h2&gt;

&lt;p&gt;If you think in a programming language as the subconscious agreement of its community, the key part is the way of working and &lt;strong&gt;approaching programming as a group&lt;/strong&gt;. In the same way that the Java community is used to work in a way by defining factories, beans, etc… The Haskell community is used to work in their own way too. It is not wrong, or incorrect, they have their own goals.&lt;/p&gt;

&lt;p&gt;The issue is, that documenting technology is easy, &lt;strong&gt;changing the minds of an entire community is not.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm a single person trying to fix the world. I have limited time and energy, and I don't want to be changing the views of anyone. I'm doing this in my free time, time that I dedicate to be more happy. &lt;strong&gt;Convincing people doesn't make me happy.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm building a wagon that is open for everyone who wants to hop on and support it, but I don't want to deal with people that don't.&lt;/p&gt;

&lt;p&gt;I want to establish a new concept so it is easier for newcomers to find resources and get up and running in the most effective way possible, all while feeling unstoppable because they're using a tool that they love.&lt;/p&gt;

&lt;p&gt;In response to any skepticism from the Haskell community, I understand the seen sufficiency of Haskell in its present state given their context and experience. Most of them are very smart people, and great professionals, and &lt;strong&gt;they are completely right to think in that way.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;However, when considering individuals with diverse approaches to software development, like those viewing programming languages as tools, or those valuing release speed over perfection, including early-career developers with abundant creative ideas, &lt;strong&gt;the priorities noticeably shift.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;NeoHaskell is focused on enabling swift and assured releases, valuing &lt;strong&gt;user-friendliness and practicality over aspects like precision, code accuracy, and complex type-level code for the sake of perfection.&lt;/strong&gt; The project recognizes that developers have varied needs, and it commits to catering to those prioritizing efficiency and feasibility in bringing their visions to life.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwberrn0l15ky6m5dmpzo.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwberrn0l15ky6m5dmpzo.jpeg" alt="a photography of a two colorful persons collaborating in the middle of a grayscale office" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What are you trying to solve exactly?
&lt;/h2&gt;

&lt;p&gt;There are &lt;strong&gt;too many entry points&lt;/strong&gt; to a simple task as running your code, such as plain GHC, Cabal, Stack, Nix, etc., each presenting its learning curve and absence of a recognized superior option. The environment is further compounded by multiple &lt;strong&gt;language extensions&lt;/strong&gt; and different frameworks handling side effects. These, combined with the daunting mathematical concepts in the language, &lt;strong&gt;often discourage newcomers.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not even mentioning even more niche workflows like mobile apps, web apps, and even game development, &lt;strong&gt;that are there&lt;/strong&gt;, but are hidden deep down under layers of accidental complexity.&lt;/p&gt;

&lt;p&gt;NeoHaskell counters these challenges by introducing a &lt;strong&gt;unified CLI tool that simplifies everything&lt;/strong&gt;, from installing the required compiler to managing packages and running tests. It streamlines all the different workflows through official templates, so one can get started right away with the task that they want to do.&lt;/p&gt;

&lt;p&gt;We aim to support newcomers by providing &lt;strong&gt;analogies to other languages&lt;/strong&gt; and featuring these in the documentation to facilitate comprehensive learning, while &lt;strong&gt;renaming or discarding terms that would be unnecessarily complex for newcomers.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fauofwchu4fzl4dha5y9h.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fauofwchu4fzl4dha5y9h.jpeg" alt="a photography of a colorful computer in the middle of a grayscale computer scrapyard" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How are you trying to solve it?
&lt;/h2&gt;

&lt;p&gt;NeoHaskell’s development is centered around the principle of catering to its community, the NeoHaskell community, avoiding the trap of &lt;strong&gt;chasing unrealistic perfection&lt;/strong&gt; and ending up with an unused product after years of development.&lt;/p&gt;

&lt;p&gt;The main goal is to create many different pieces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A remarkable standard library&lt;/li&gt;
&lt;li&gt;An integrated CLI tool with precise error messages&lt;/li&gt;
&lt;li&gt;Templates with planned architectures&lt;/li&gt;
&lt;li&gt;Documentation with a set of recipes&lt;/li&gt;
&lt;li&gt;Mobile app packaging&lt;/li&gt;
&lt;li&gt;Python interoperability&lt;/li&gt;
&lt;li&gt;And many more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These objectives, though ambitious, are attainable by &lt;strong&gt;delivering small increments&lt;/strong&gt; and focusing on fostering one essential element: developer joy.&lt;/p&gt;

&lt;p&gt;Rather than promoting the creation of new architectures and the innovative use of advanced features, NeoHaskell favors well-established patterns in the software industry and embraces functional programming where appropriate, allowing for imperative code where it’s more suitable. Comprehensive documentation, a supportive Discord community, and &lt;strong&gt;a philosophy of "if it takes more than 15 mins to figure out, it is a bug"&lt;/strong&gt; are the key points to ensure the success and happiness of its users.&lt;/p&gt;

&lt;p&gt;One of the key ideas of NeoHaskell is to &lt;strong&gt;reuse as much technology as possible&lt;/strong&gt;, while staying in the realm of NeoHaskell. This approach opens up many paths, and leads you very far. Our goal is to be happy while coding what makes our project different, not all the bullshit that just gets in the way. If your goal is to make a todo-list mobile application in the most joyful way, using NeoHaskell, you shouldn't think at all in how the rendering of the view is actually implemented. &lt;strong&gt;Even if the mobile app is a React Native renderer of HyperView XML views that are retrieved from a 100% NeoHaskell backend,&lt;/strong&gt; as shown in this tweet:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1700859705021571543-637" src="https://platform.twitter.com/embed/Tweet.html?id=1700859705021571543"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1700859705021571543-637');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1700859705021571543&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;When you approach development like this, by &lt;strong&gt;doing concessions, instead of closing doors&lt;/strong&gt;, you open up the door for innovation and improvement, while maintaining a healthy and productive ecosystem. The other way around, you end up with a wasteland filled of gardeners ensuring that someday, the plants will grow &lt;strong&gt;exactly in the perfect way that they want.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flszxtla8ns6biesumc23.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flszxtla8ns6biesumc23.jpeg" alt="a photography of a colorful flower in the middle of a grayscale desert" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How does it piggy-back the Haskell ecosystem?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;NeoHaskell preserves 100% compatibility with Haskell&lt;/strong&gt;, seamlessly integrating existing packages and tools designed for Haskell. However, &lt;strong&gt;its goal is not to be backward compatible&lt;/strong&gt;. It will refine several elements from the Haskell standard library, with functions being renamed, certain operators being concealed and new ones introduced, and type classes being restructured to ensure their practical applicability, if they are applicable.&lt;/p&gt;

&lt;p&gt;NeoHaskell will actively utilize &lt;strong&gt;compiler plugins&lt;/strong&gt; to modify the compiler’s behavior to align more with &lt;strong&gt;newcomer friendly messages and features.&lt;/strong&gt; It will maximize the potential of existing libraries, sometimes through encapsulation or re-exportation, as well as the usage of all the plethora of &lt;strong&gt;great CLI tooling that exists for Haskell.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4cmnbpda4zp1e6o10tgy.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4cmnbpda4zp1e6o10tgy.jpeg" alt="two colorful people walking one besides another in a grayscale intrincate ornament" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How will be the design and priorization process?
&lt;/h2&gt;

&lt;p&gt;I believe that in order for a product to be successful, the design process &lt;strong&gt;must be centralized in a single person.&lt;/strong&gt; This person must listen to the users, the other designers, and in general must have an open mind to always cherry-pick all possible ideas in order to improve the product. &lt;strong&gt;I don't believe that a product should be guided by democracy&lt;/strong&gt;, and neither it should implement all suggestions by every user. In other words, I'll be the one in charge of generating and listening to discussions, and prioritizing the features of the project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I understand that this comes with some risk&lt;/strong&gt;, but at the same time I believe that all programming tools like Python and Ruby that are very loved by their communities are like that because of the BDFL model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NeoHaskell's development will be open and transparent&lt;/strong&gt;, marked by continuous sharing of progress and regular updates. My biggest priority is to &lt;strong&gt;maintain the community informed and aware of my vision&lt;/strong&gt;, not getting into some kind of spiritual retreat to code while everyone thinks that the project has stalled and I have disappeared.&lt;/p&gt;

&lt;p&gt;Anyone interested can contribute by participating in discussions on &lt;a href="https://discord.com/invite/wDj3UYzec8" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; and &lt;a href="https://github.com/neohaskell/neohaskell" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. &lt;strong&gt;Contributions go beyond code, the most important part is the design process, and that can only be achieved through communication between the members of the community.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsiuhjy8veuumfeqnhvya.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsiuhjy8veuumfeqnhvya.jpeg" alt="a colorful photography of a person making a drawing, with a crowd cheering on the background" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  I want to contribute, where is the code?
&lt;/h2&gt;

&lt;p&gt;If you've read "the project that I've been working on for many years" as "the project that I've been coding for many years", I'm sorry to disappoint you, &lt;strong&gt;that is not the case.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm glad that it isn't, because &lt;strong&gt;that would have been a complete mistake.&lt;/strong&gt; Design is a thinking process, is a communication process that goes back and forth. It is about talking to people, listening to every conversation with an open mind. Getting into tasks that you don't like and doing them for the sake of &lt;strong&gt;understanding what's going on, what are the users doing, and what is this thing that could improve their lives.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I didn't code NeoHaskell&lt;/strong&gt;, instead I wrote TypeScript, both for backend, frontend, CLI tools, infra-as-code, and many more things. I worked with enterprise clients whose teams are so big and the team member rotation is so high, that every little code pattern had to be stitched in the exact same way so there were no surprises when team members rotated. I coded plain Java, as well as Python, in the most boring and bland way possible. All of that, taking notes and gathering insights for NeoHaskell. &lt;strong&gt;That is the real&lt;/strong&gt; work. Getting all these puzzle pieces that are spinning in a tornado around you, picking them up, while attempting to stay on the ground and assembling the puzzle.&lt;/p&gt;

&lt;p&gt;There's this thing that people call &lt;strong&gt;"Haskell curse"&lt;/strong&gt;, which is the feeling of disgust for using other, inferior, technologies that aren't Haskell.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NeoHaskell lifts the curse&lt;/strong&gt;. Every interaction with technology and users from other ecosystems &lt;strong&gt;becomes a blessing&lt;/strong&gt;, and an opportunity to understand what makes us happy as software craftspeople. &lt;strong&gt;Every frustration becomes a leverage point&lt;/strong&gt; to create the most awesome language, ecosystem, and community ever in the world. So, check out &lt;a href="https://neohaskell.org" rel="noopener noreferrer"&gt;the website&lt;/a&gt;, &lt;a href="https://discord.com/invite/wDj3UYzec8" rel="noopener noreferrer"&gt;join the Discord&lt;/a&gt;, and hop into &lt;a href="https://github.com/neohaskell/neohaskell" rel="noopener noreferrer"&gt;the project's GitHub&lt;/a&gt;, this is not possible without you (literally).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiitx3deybgc7al7bil3e.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiitx3deybgc7al7bil3e.jpeg" alt="a colorful photography of a wiccan magician in a spell circle performing magic" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Afterword
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Writing this post was not easy at all.&lt;/strong&gt; I'm very happy that this project finally sees the light, because I truly believe since the day I discovered Haskell in that old dusty book in my faculty's library, that it has the power to be the leading language in software industry. You cannot imagine how many different attempts that I've tried, how many prototypes I actually wrote, and how many conversations I had with developers who thought that Haskell is just hipster bullshit that is not useful at all.&lt;/p&gt;

&lt;p&gt;If you've read this far, &lt;strong&gt;let me thank you from the deepest part of my heart&lt;/strong&gt;, even if you don't believe in this project, or you're not interested, and if you are, &lt;strong&gt;have this huge virtual hug and let's chat!&lt;/strong&gt; I'm eager to talk with people that are interested in this idea.&lt;/p&gt;

&lt;p&gt;NeoHaskell may evolve as a specialized community or may blossom into something more extensive and mainstream.&lt;/p&gt;

&lt;p&gt;My hopes are humble: for it to &lt;strong&gt;serve as an invaluable resource enabling the community to experience continual satisfaction&lt;/strong&gt;, and for it to encourage the Haskell community to emphasize practicality and inclusivity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwjdfvuh36lfkys6vdn1x.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwjdfvuh36lfkys6vdn1x.jpeg" alt="a colorful close up photography of two hands holding the heart emoji" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you, really,&lt;br&gt;
NickSeagull&lt;/p&gt;

</description>
      <category>programming</category>
      <category>discuss</category>
      <category>opensource</category>
      <category>haskell</category>
    </item>
  </channel>
</rss>
