Derw, a friendly ML-like language for the web, status: January 2022, part 2
In the second half of this month, I give my thoughts on new languages in the same space as Derw, configurability and my workflow. Improvements made to Derw were mostly bug fixes and examples. The first half of this month’s changes were covered here. The best place to stay up to date in on Twitter or by staring the Derw repo.
If you’ve just arrived here, Derw is a programming language in the ML family designed to enable better workflows with TypeScript codebases. If you’re wondering why, check out my blog post about exactly that. These blog posts are split into three parts: a changelog, some thoughts, and some meta comments on language development. Follow the blog with the button below.
Changelog
New example: Jeopardy dashboard
I’m always on the watch out for examples to reproduce in Derw, especially those which were originally written in Elm. When I came across this Jeopardy tool written in Elm, I knew that I could quickly port it to Derw with few changes, making it a good example of how you might rewrite a project into Derw from Elm. So here it is.
This inspires some bigger ideas that I’ve been thinking about for a while. In theory, porting Elm to Derw should be very straightforward, something that could be done by tooling. The API for Coed (which Derw’s html library is based on) is very similar to Elm’s. The standard library shall be similar, too, once it’s ready.
Bash completions
I added Bash completions for Derw when being run as a global command. I’m not sure how to distribute them without using postinstall, so for now I just recommend cloning that repo and amending your bashrc/bash_profile file to load them. Later on, the plan is to add autocomplete for package names as I did for Elm bash completions, and autocomplete for running individual tests. Tests should be a relatively minor change, but package names depends on me setting up package infrastructure beyond just using Github.
Type tokens in type aliases
When parsing types, the flow currently looks something like tokenize => filter out non-type tokens (e.g whitespace). The raw type tokens are then parsed into two groups: regular type tokens, and function type tokens. A regular type token might be an identifier, or nested identifiers (e.g `List a`). A function type token is composed of a collection of regular type tokens. The code for this was a bit complicated, and I found that it didn’t work in every use case, for example when a type alias had a property that was a function. So I rewrote it all.
Misc
`derw init —dir <dir>` will now amend the .gitignore of <dir> rather than the current working directory’s
Properties of type aliases can be functions
Added some functions to Dict
Added length for Lists
Moved format out to its own cli command
Derw generation of nested function calls now get wrapped in brackets
Object update syntax
Thought cauldron
Configurablity
One of the great things about Elm is the simplicity of the tooling. Generally Elm tooling follows the principle of “there should be one way to do things”, and that it should be obvious how to use it. Every time I see a new tool in my stack that requires a complicated configuration file with words like plugins and transformations, I instinctively want to get off the ride.
Every time you add a new configurable option, you fracture the user base. You might be using the same tool, sure, but if you don’t have the same plugins loaded in the same order, you’re working with a totally unique setup. So when someone comes along and says “I have X problem with Y”, you have to ask them “do you have Z plugin in W order?”.
In Derw, the plan is to keep things simple. Only a singular configuration file format with no optional fields. The tooling should have good defaults based on the package file. All arguments to each CLI command should be done via named flags, so it’s easy to understand which arg does what. I also follow the double-diamond approach: start wide, then redefine down to the core set of commands and flags needed.
Other languages
I’ve always been interested in keeping up to date with new or novel programming languages. It’s how I ended up involved with Elm. Prior to university I mostly only knew Python, PHP, VB 6 and C. It wasn’t until I had the plentiful free time that university provided that I got properly involved with Hindley-Miller languages like Haskell and Idris. I found the types to be one of the bigger influences on my programming style: instead of types being about encapsulation, suddenly they were leading the implementation of functions.
After finding Elm, it became my main language for a good chunk of time. I remember sitting at React Europe when Redux was announced, and thinking to myself “this is Elm but in Javascript”. At the time, I remember feeling slightly annoyed that Elm wasn’t mentioned. I think it’s important to credit where ideas come from, because chains of knowledge tend to come from that. For example, if you look at Haskell’s comprehensions after learning about Python’s, you’ll be able to see the differences and have a clearer idea of which you like more. The same goes for Redux and Elm: if those at React Europe that day saw some Elm code, perhaps more people would’ve been inspired by Elm’s patterns, or would be inspired to use Elm. The whole idea of references in research papers is built around this concept of building upon existing work, after all.
When you’re working on a library, I find that I either have two thought patterns: 1) how do alternative solutions solve this problem, or 2) I don’t want to be influenced by alternative solutions. 2 is a silly idea, most of the time. As programmers over time, we will develop similar solutions to others no matter what we do, because at the end of the day, most languages and their implementations are pretty similar. So in the Redux case, it was probably natural that functional frontend code would lean towards the MVU pattern. But as a developer, I want to understand how this pattern can be used - and the different workflows it enables.
That leads me back to 1, which I’m also interested in achieving with Derw. My main knowledge of language design comes from papers I’ve read, along with discussions about compilers, and having implemented a number of compilers in the past. I’m by no means an expert, but I know enough to get things done — and in the name of being pragmatic, that’s all I need right now. In Elm, I’ve previously implemented 3 compilers. In Haskell, just 2. But the knowledge from those compilers has given me enough of an idea of how you implement a pure compiler. As a result, the Derw compiler is pure, except for when dealing with CLI.
But that isn’t to say that Derw isn’t influenced by other languages. The clear two primary languages inspiring Derw are Elm and Typescript. Derw is 80% Elm, 15% Typescript, 5% Haskell. There are other languages out there implemented in Elm, like Ren, Stabel, and Elm-in-Elm. I haven’t looked at the source for these too much, but when it comes to self-hosting Derw, I’ll probably have a look. There’s also languages which fufill a similar niche to Derw, like Bagel. Bagel aims to solve Javascript in a similar manner to Elm when FRP was supported, which is neat. The syntax at the moment looks more like Javascript than ML, so Derw and Bagel fall into different categories. But I’m keeping an eye on it!
Meta
Release radar
Github has a release radar that you can submit packages to, in order to be featured in a blog post. Derw is not at the point where announcing releases makes sense, but when it is, I’ll remember to submit it there. I doubt that there will be much traffic from the release radar itself, but it’s worth trying out.
Recovering from Covid vaccine
I was making good progress earlier this month, until I had my booster shot. I broke my leg late last year, so going to the booster center involved a couple of days walking solo outside for the first time in several months, so that I could investigate the ice patches and tall bridge in the way. Luckily there was no ice at all, until I got about 40m from the center, at which point it was solid ice. I had predicted this might be the case, so I had left about an hour earlier than necessary and took my time. The booster itself was quick and painless, but a few hours later I came down with a fever which remained for a couple of days and made coding difficult. I lost motivation a couple of days after, too, when I knew that my next big planned change would take a lot of refactoring. I made a start on that when I felt healthier, but in the meantime I did some small fixes instead.
As someone who regularly accidentally flips his sleep schedule, it’s important for me to avoid coding late at night. Sometimes it happens still, but it’s healthier if I don’t. So on days when I’m feeling beat, I tend to not do much coding outside of work. There was a time where I tried to make a commit every day, and I believe my streak was around 120 days. But this is not a realistic way of working. So now what I do instead is simpler: mentally note tasks which should be relatively easy to do on auto pilot, and when I’m low energy, work on those rather than the complicated issues.