← Back to context

Comment by howerj

2 days ago

Is there an implementation of an APL language (or other any other array language) written in *readable* C that is around 1000 LoC? There are for LISP, FORTH, Prolog, TCL and the like.

Unlikely, at least for what I think you mean by "readable" here.

APL isn't really one of these exhibitions of computational simplicity in the way of the languages you mention. It's inventor, Kenneth Iverson, was more focused on the human side of thinking in and using the language.

Forth, Lisp, et al are quite easy to implement, but they require considerable library layers on top to make them useful for expressing application-level logic, even if we just focus on the pure functions. APL, on the other hand, has a larger core set of primitives, but you're then immediately able to concisely express high-level application logic.

Are you looking for a kind of reference implementation for learning purposes? If so, I'd say the best route is just go with the docs. Arguably the Co-dfns compiler is a precise spec, but it's notably alien to non-practitioners.

  • Any pointers on how to get better at expressing high-level application logic in APL? Any good resources on programming in APL? So far I have only found tutorials and basic stuff for learning APL but not much on applying APL. I am slowly improving and think I sort of get it but probably don't.

    • Not that I know of, unfortunately. This is, IMHO, the biggest pain point of APL pedagogy at the moment. I'm actually working on some resources, but they're still gestating.

      For non-event driven systems, the short story is to organize application state as a global database of inverted tables and progressively normalize them such that short APL expressions carry the domain semantics you want.

      For event driven systems, we have token enumeration over state machines, which can be expressed as literal Branches to state blocks.

      Granted, the above likely doesn't communicate well unless you're already primed with all the necessary ideas. If you're interested, I'm willing to chat. Email is in my profile description.

      source: Current day-to-day is greenfield APL dev.

      2 replies →

Beyond what others have mentioned, I think another big differentiating factor between APL and the rest of those languages is that APL isn't focused on allowing the user to expand the language meaningfully, but rather on being a well-rounded language by itself (which is how it can be reasonably useful without objects with named fields, mutation, explicit loops (or only gotos in APLs infancy!), no first-class functions, no macros, and only one level of higher-order function (though of course most APL implementations have some of those anyway)).

As such there's really no pretty "core" that pulls its weight to implement in 1000LoC and is useful for much.

Here's a simple minimal APL parser in JS that I wrote once to display one way of parsing APL: https://gist.github.com/dzaima/5130955a1c2065aa1a94a4707b309...

Couple that with an implementation of whatever primitives you want, and a simple AST walker, and you've got a simple small APL interpreter. But those primitive implementations already take a good chunk of code, and adding variables/functions/nested functions/scoping/array formatting/etc adds more and more bits of independent code.

Perhaps if you accept defining bits in the language in itself via a bootstrap step, BQN is a good candicate for existing small implementations - a BQN vm + minimal primitive set is ~500LoC of JS[0] (second half of the file is what you could call the native components of a stdlib), 2KLoC for first public commit of a C impl[1], both of those having the rest of the primitives being self-hosted[2], and the compiler (source text → bytecode) being self-hosted too[3]. (the C impl also used r0.bqn for even less required native primitives, but modern CBQN uses very little of even r1.bqn, having most important things native and heavily optimized)

[0]: https://github.com/mlochbaum/BQN/blob/master/docs/bqn.js though earlier revisions might be more readable

[1]: https://github.com/dzaima/CBQN/tree/bad822447f703a584fe7338d...

[2]: https://github.com/mlochbaum/BQN/blob/master/src/r1.bqn (note that while this has syntax that looks like assigning to primitives, that's not actual BQN syntax and is transpiled away)

[3]: https://github.com/mlochbaum/BQN/blob/master/src/c.bqn

ngn's k is publicly available, around 1000 lines and readable, in that I can read it.