Dev.to · 4 min read

I Didn't Mean to Build a Programming Language

I Didn't Mean to Build a Programming Language

I'm building a programming language. Written like that, it sounds as if I had always dreamed about compilers, read the Dragon Book cover to cover, and spent years waiting for the day I could finally design my own language. Not even close. I was just writing ordinary web applications and constantly thinking things like: "Why do I have to write it this way here?" or: "Wouldn't this feel better if I could write it a little more directly?" I kept digging into those small annoyances instead of ignoring them, one by one, and somehow they turned into a programming language. It's called Seseragi. Seseragi (せせらぎ) is a Japanese word for the gentle sound or flow of a small stream. I wanted my programming language to have a Japanese name. https://github.com/KentaroMorishita/seseragi https://seseragi.vercel.app/ https://seseragi.vercel.app/tour/ It's still experimental and pre-release, but a Rust compiler, CLI, LSP, formatter, WASM Playground, Signal, and Web UI are already working to a surprising degree. Even I sometimes look at it and think, "How far is this thing going?" It started with being tired of if In 2024, I wrote this article on Qiita. https://qiita.com/KentaroMorishita/items/6329d20fbc6f98f72864 The title alone probably tells you I was already heading somewhere weird. I don't think I hated if itself. What bothered me was the feeling of tracing conditional branches as statements. That was also why I liked ternary expressions. Not just because they were short. They were expressions, so I could take the result directly as a value. const label = isLoading ? "Loading..." : hasError ? "Error" : "Ready" Of course, once these grow, they become painful too. So I started building my own match and when abstractions on top of TypeScript. Looking back, I was trying pretty hard to fight the language. But the underlying desire was already clear: I'd rather construct values than chase control flow. When I look at Seseragi now, the symptoms had started long before the language existed. There was a period when I thought about monads on the train every day Around the same time, I spent about three months thinking about monads during my commute. I didn't need them for work. Nobody told me to study them. I just got curious and started talking things through with GPT every day. This is probably where things got even stranger. Functor. Applicative. Monad. At first I only wanted to understand the terminology. Then the question slowly changed into: "Wouldn't it feel good if I could just use this naturally in TypeScript?" Eventually, thinking about it wasn't enough anymore. So I built F-Box on top of TypeScript That became F-Box. https://github.com/KentaroMorishita/f-box-core https://github.com/KentaroMorishita/f-box-react Maybe, Either, Task, , , >>=, and do notation. I wanted values to compose as directly as possible inside TypeScript. I even wrote articles like these on Zenn. https://zenn.dev/ken_morishita/articles/568efda2211f6d https://zenn.dev/ken_morishita/articles/34a0860d7e7731 What was I doing? Still, the time I spent building F-Box turned out to matter a lot. You can do quite a lot in TypeScript if a library works hard enough. You really can. But the harder I pushed the library, the more another thought kept coming back: Maybe this isn't the library's job. The harder the library worked, the more visible the language boundary became You can implement Maybe in TypeScript. You can implement Either. You can implement Task. You can curry functions. You can even imitate do notation with a library. But underneath all of that, you're still standing on TypeScript's syntax and semantics. At some point, what I wanted was no longer a "useful library." I was thinking about more fundamental things: I want the shape of data to be written directly. I want branching to feel like working with values. I want failure to stay visible as a value too. I want interactions with the outside world to be visible from the type. If state changes over time, I want that to still feel like an extension of values. I don't want UI code to suddenly drop me into a completely different world. If that's what I wanted, maybe I should just make a language where those things are normal from the beginning. Would that be faster? No. Absolutely not. I started anyway. Then I started building Seseragi Seseragi currently looks something like this: fn fizzBuzz number: Int -> String = match (number % 3, number % 5) { (0, 0) -> "FizzBuzz" (0, _) -> "Fizz" (_, 0) -> "Buzz" _ -> `${number}` } pub effect fn main = for number

This is a summary aggregated from Dev.to. Read the complete article on the original site:

Read full article at Dev.to

More AI & Machine Learning News