I've had a few major changes in my life recently. One of the more minor ones—rewriting the tool I made to write academic papers in a controlled LuaLaTeX environment—has made me reconsider what I consider to be "my" programming languages: The languages that, should a project not require a specific language, are the ones I would choose from, personally.
(define (bluebird action procedure) (lambda* (#:rest args) (apply action (list (apply procedure args)))))
Thinking about it with some introspection, I think this concept became wedged in my brain back in high school when I happened upon Eric S. Raymond's "How to Become a Hacker", with it's "Learn How to Program" section. It outlined languages and categories thereof in a way that helped me cement Epigram 19 as an opinion I shared. In my adult life, I have been searching constantly for languages that change how I think about programming.
In that time, I have come across and tried out many languages: Starting with C++ (I know), I then moved forward with everything from Clojure to BQN, as my search for a set of languages that spoke to me continued. I found that I tend to like languages that don't offer too much tooling as a core part of their language: Clojure's leiningen and Erlang's OTP felt like putting on a sweater that had shrunk in the wash to me. I also found that I had a few major technical requirements: Unicode support meant a lot to me, as did reproducability and a libre-adjacent license.
When it came down to it, though, I think the most important factor to me was whether I enjoyed using the syntax or not. This is also probably the thing that took me the longest to decide about a language, as there is no accounting for taste in a quantifiable way. However, I do know that boilerplate is something I'm not a huge fan of, especially if that boilerplate is something I just need to retype in every new file. I'm also a big believer in notation as a tool of thought, and so the myriad languages with an ALGOL-like syntax did not interest me nearly as much as those that forced me to learn how their syntax worked.
∇Z←WithTax ⍵;Rate;A;B;Cost ⍝ Calculate the price of an item including a 7% sales tax. ⍝ ⍝ This is a CALCULATION. ⍝ ⍝ Arguments ⍝ ========= ⍝ ⍵ <number>: The price (in dollars) of the item before tax. ⍝ ⍝ Local Variables ⍝ =============== ⍝ Rate <number>: A decimal representation of the sales tax rate. ⍝ Cost <number>: The cost of the item without tax, in cents. ⍝ A <number>: The exact cost with tax, in cents. ⍝ B <number>: The price with tax in cents, rounded up to the nearest cent. ⍝ Returns ⍝ ======= ⍝ Z <string>: The full price of the item with tax, in dollars. ⍝ ⍝ Impurities ⍝ ========== ⍝ None. ⍝ ⍝ Assume a 7% Sales Tax. Rate←0.07 ⍝ Convert the cost to cents for precision. Cost←⍵×100 ⍝ The Main Calculation: Add the Amount to 7% of the Amount. A←Cost + Cost × Rate ⍝ Round up to the nearest cent. B←⌈A ⍝ Present the result in dollars. Z←10 2⍕(B÷100) ∇
That said, for me, Guile Scheme has become the language I reach for most often. It is the language my OS is configured and largely written in, the language the tools I create are generally written in, and in general the "default" language I would use when implementing an idea. It suits me very well in terms of portability, performance, syntax (Yeah, I'm a LISPer), and general vibe. But it is not the only language I want to use.
I was listening to an episode of the Array Cast where the guest said something that resonated with me:
If you look at k especially and FORTH, these are both languages that are made by eccentric creators with their own highly distinct style of problem solving that is centered on this idea of radical minimalism. In FORTH, you bend the problem in order to suit the language and the language to suit the problem. In order to try to find a balancing point where the entire system is as simple as possible. And in terms of languages, you know, FORTH is generally considered to be a pretty low level language. Although you can build it up to be suitable for a specific application. You know k is a comparatively, high level language, and frequently you're able to just solve problems directly in the language without introducing abstractions. But in both cases it's a system that has been like viciously attacked over its evolution. Constantly hacking things off and throwing away anything that doesn't carry its weight. So you end up with this thing that is uhm, you know. Instead of continuously growing and getting larger and more powerful, it is staying about the same size and becoming sharper and more effective.
The feelings I experienced when I heard that quote were astounding. I wholeheartedly agreed, and with that, FORTH and k became languages I had to use. In many ways, the above comments can apply—albeit in a more theoretical way, as opposted to the technical way they are presented and used there—to Scheme as well. I guess that's me niche, in the end.
In addition to these three—the core of my current toolset—I am also going to choose a few more mainstream languages for less verbose reasons: C is the language of UNIX, and is so prolific and portable that it would be a mistake to exclude it. It will fill the portable and high-performant compiled language for me very nicely. GNU APL is the non-ASCII Array Language I have felt the most comfortable using, and works well for scripting and prototyping more complex concepts. Uxn is the virtual machine I like the most, and it most aligns with my goals, so uxntal is the VM language I will use. Emacs Lisp for my editor (obviously) and Bash for my Shell (yup). Which just leaves the matter of the purely functional language—which will serve as the language for theoretical, provable concepts and formalizations—between OCaml and Haskell…
I'll be honest here, I haven't been successful in my attempts to use either of these titans at this point, and for a few reasons. First is the matter of tooling, as mentioned above: OCaml's dune and Haskell's cabal are both very opinionated about directory structure, dependencies, and such. Integrating them with my OS, GNU Guix, means I not only need to learn the tooling, but also how to subvert it to allow for fully reproducable builds. There's also the matter of Unicode, where Haskell has had full support for a long time, and OCaml has only recently added it. Then there is the effort to build both of these: GHC takes a calendar year (hyperbole) to compile on a local machine—even moreso on the low-powered ARM machines I have—whereas OCaml is quicker and available as a substitute for ARM64 currently.
So, I guess, for now, OCaml wins. But I am open to other opinions, if You have good points to share.
In summation, my languages at this time are:
- System Programming, FFI, High Perf and Port.
- Emacs Lisp
- Editor Config
- Stack Language, Minimal System
- GNU APL
- Unicode Array language, Scripting
- Guile Scheme
- Default language, Scheme, Lisp
- ASCII Array Language, Minimal System
- Functional, Formalization
- VM, Assembled Language