[HN Gopher] APL Interpreter - An implementation of APL, written ...
___________________________________________________________________
APL Interpreter - An implementation of APL, written in Haskell
(2024)
Author : ofalkaed
Score : 130 points
Date : 2025-06-05 21:22 UTC (1 days ago)
(HTM) web link (scharenbroch.dev)
(TXT) w3m dump (scharenbroch.dev)
| behnamoh wrote:
| Depending on your personality type (perfectionist or pragmatic),
| this is either the best of both worlds or the worst.
| valcron1000 wrote:
| My favorite language used to interpret my most hated language
| (used both professionally).
|
| There are several things I disagree with regarding Haskell but
| it's understandable given that this is OP's first time using the
| language (like a "monad's internal state"), but I want to
| highlight one particular observation:
|
| > This uncertainty of time of evaluation also makes catching
| errors difficult, because calling catch on the function that
| throws the error will not necessarily catch that error
|
| It's important to distinguish between imprecise exceptions (ex.
| calls to `error `, `undefined`, and the like) and synchronous
| exceptions (async exceptions are not important for the article).
|
| > Catch must be called on the function that forces evaluation on
| that error. This is something that is hard to trace, and
| something that types don't help much with.
|
| The types are actually the most important part here! Synchronous
| exceptions cannot be thrown by pure code (as long as we're not
| dealing with escape hatches like `unsafePerformIO`), while IO
| code can throw and catch all kind of exceptions .
| tome wrote:
| Regarding catch, yes, I agree types help, but they can help
| even more! I suggest an IO-wrapper effect system (mine is
| called Bluefin; effectful is also a good choice). Then there is
| absolutely no ambiguity about where an exception can be
| handled. There is exactly one place -- no more, no less. It
| makes dealing with exceptions very easy.
|
| https://hackage.haskell.org/package/bluefin-0.0.16.0/docs/Bl...
| instig007 wrote:
| > Apparently Haskell's performance isn't that bad, but I don't
| plan on using Haskell for anything that is remotely performance-
| sensitive. Trying to optimize Haskell code does sound like an
| interesting problem, but it might be a lost cause.
|
| When the dude uses `foldl` over lists and `foldr` with `(*)`
| (numeric product) it is not the language that's the lost cause.
| kccqzy wrote:
| In case anyone who doesn't know Haskell: both of these are
| beginner level mistakes. Using `foldl` causes space leaks and
| turns your O(1) space algorithm to O(N) space for no good
| reason. And using `foldr` over lists is good when you are
| dealing with unevaluated lists and want list fusion, but not
| when they already exist in memory and will continue to do so.
| And that doesn't even include the obviously wrong choice of
| data structure, built-in Haskell lists are singly-linked lists
| not arrays. There are Array types and Vector types (both come
| with GHC so no extra dependency needed) that are more
| appropriate for implementing APL in the first place.
| itishappy wrote:
| > And using `foldr` over lists is good when you are dealing
| with unevaluated lists and want list fusion, but not when
| they already exist in memory and will continue to do so.
|
| What's the preffered approach?
| farrellm23 wrote:
| Usually you want `foldl'` (with ' at the end), the strict
| version of `foldl`. It prevents the creation of
| intermediate thunks, so effectively a tail recursive
| iteration over the list in constant space.
|
| `foldr` I almost never use, but it would be for: the return
| value is a lazy list and I will only need to evaluate a
| prefix.
| zoul wrote:
| The naming conventions are nicely sadistic.
| WorldMaker wrote:
| This is what happens when you let Mathematicians name
| things on chalkboards. They don't want to run out of
| chalk and they get tired of spelling whole words very
| easily so they use short names and silly symbols. The
| name foldl' is "just" "fold left prime". Remember ' means
| "prime" from calculus class and thinking that was silly
| even then? Accidentally infected Haskell at a young age.
| Rendello wrote:
| > This is what happens when you let Mathematicians name
| things on chalkboards.
|
| Doubly so with APL!
| kccqzy wrote:
| Yeah it's definitely unusual to allow ' to be part of the
| name of a variable, especially considering that it is,
| like C, the quote for character types.
| tome wrote:
| I have the definitive answer to this question in my article
| "foldl traverses with State, foldr traverses with anything"
|
| https://h2.jaguarpaw.co.uk/posts/foldl-traverses-state-
| foldr...
|
| In short: use foldl' when you're iterating through a list
| with state. foldr can be used for anything else, but I
| recommend it for experts only. For non-experts I expect
| it's easier to use for_. For more details about that see my
| article "Scrap your iteration combinators".
|
| https://h2.jaguarpaw.co.uk/posts/scrap-your-iteration-
| combin...
| kccqzy wrote:
| Is it really easier to use for_? It forces you to think
| about effects rather than pure data. So you end up
| packaging data into effects through State or similar
| monads. So is it really easier if you force people to use
| Monad (well technically Applicative)?
| pierrebeaucamp wrote:
| > When the dude uses `foldl` over lists and `foldr` with `(*)`
| (numeric product) it is not the language that's the lost cause.
|
| This is a great example of Haskell's community being toxic. The
| author clearly mentioned they're new to the language, so
| calling them a "lost cause" for making a beginner mistake is
| elitist snobbery.
|
| I usually don't point these things out and just move on with my
| life, but I went to a Haskell conference last year and was
| surprised that many Haskell proponents are not aware of the
| effects of this attitude towards newcomers.
| instig007 wrote:
| > calling them a "lost cause" for making a beginner mistake
| is elitist snobbery.
|
| I wonder how do you call the practice of complete beginners
| spreading FUD and suggesting to their readers that something
| in the language is "a lost cause", all whilst having neither
| enough knoweldge nor sufficient practice to make assumptions
| of this kind.
|
| > This is a great example of Haskell's community being toxic
|
| To be clear: I don't represent haskell community, I'm not
| part of it, and I couldn't care less about it. It just so
| happened that I saw the author inflating their credentials at
| the expense of the language via spreading FUD, that the
| beginners you seem to care about are susceptible to, and I
| didn't like it.
|
| If you get triggered by the expressed dissatisfaction with
| the author's unsubstantiated presumptuousness, reflected back
| at them in a style and manner they allowed themselves to talk
| about the thing they don't know about, then it's purely on
| you and your infantilism.
| tome wrote:
| Can I ask which conference? Did people behave towards you in
| that way at that conference, or are you referring to
| behaviour online? I will try to use whatever authority I have
| in the Haskell community to improve the situation.
|
| (Still, hopefully in this case it's clear from instig007's
| reply that it's not a member of the Haskell community
| behaving in that way.)
| pierrebeaucamp wrote:
| This is almost exclusively just online behaviour. Everyone
| I met in person is very nice :).
|
| The conference I mentioned was ZuriHac. After the key-note
| Q&A there was a small hallway discussion around how to grow
| the adoption / reach of Haskell. The conversation revolved
| around mostly technical points (like how Haskell is
| superior to x, because of y). What I found interesting was
| that there was little to no talk about the steep learning
| curve, developer ergonomics or business use-cases.
|
| The thing is, if someone has not yet learned about
| functional programming, strong type systems or category
| theory, why / how would they see the advantages or the
| power of pure functions, lazy evaluation, Monads, etc. At
| the same time, their opinions or struggles are often
| dismissed due to their lack of knowledge. The parent
| comment is a prime example of this.
|
| Edit: This is a great 10-minute talk that touches on the
| general topic: https://www.hytradboi.com/2025/419859c5-6a8f
| -4a49-b324-0f225... She covers a lot of this better than I
| can.
| kccqzy wrote:
| Newcomers need the self-awareness to understand that they are
| newcomers and that their opinions are more often than not
| wrong. This author doesn't have that humility.
|
| It is simply aggravating to see newcomers without humility
| speak with an authoritative tone on subjects they barely
| know.
| howerj wrote:
| 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.
| ofalkaed wrote:
| Not that I have found, closest is an incomplete one done in
| python.
|
| https://mathspp.com/blog/tag:lsbasi-apl#body-wrapper
| itishappy wrote:
| What, you don't like Arthur's style?
|
| https://www.jsoftware.com/ioj/iojATW.htm
|
| https://github.com/kparc/ksimple/blob/main/ref/a.c
|
| Slightly less factiously, the ksimple repository has a version
| with comments.
|
| https://github.com/kparc/ksimple
|
| https://github.com/kparc/ksimple/blob/main/a.c
|
| Note, these aren't APL, but they are in the same family of
| array languages.
| xelxebar wrote:
| 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.
| ofalkaed wrote:
| 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.
| xelxebar wrote:
| 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.
| ofalkaed wrote:
| >IMHO, the biggest pain point of APL pedagogy at the
| moment
|
| It is the one that always trips me up. I just started in
| on my third attempt at learning APL/array languages, both
| previous times I got to the same point where I was mostly
| at a loss of how to apply it all. So I move on and forget
| all that I learned until the next time and have to start
| over. Thankfully the last attempt seems to have mostly
| stuck as far as keyboard layout goes, makes progress much
| quicker.
|
| I may take you up on that email offer once I get a bit
| further along in this current attempt, can't quite form
| reasonable questions yet and only know what tripped me up
| in the previous attempts. I believe you are a regular on
| APL Orchard? I will be joining it soon so perhaps will
| see you there.
| xelxebar wrote:
| Yes, I'm one of the few regularly in the Orchard. There's
| also the APL Farm discord, which is chattier.
|
| In the off chance you've not see this:
| https://aplwiki.com/wiki/Chat_rooms_and_forums
| geocar wrote:
| What would you consider "high-level application logic"?
| ofalkaed wrote:
| The logic of the system instead of the pieces of the
| system; how the language's core data structure
| applies/relates towards expressing that system. I could
| very well be overthinking things and seeing some sort of
| magic which is not there but this line in the previous
| response to me, makes me think I am still missing a piece
| of the puzzle:
|
| >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.
| gitonthescene wrote:
| I may be reading too much into this but it sounds like
| you're searching for templates to stimulate ideas similar
| to how there are examples for smaller puzzle type
| problems.
|
| I think most sizable stuff is proprietary. I implemented
| an lsp in an open source K which uses json/rpc. But the
| open source K is probably best considered a hobby
| project.
|
| https://github.com/gitonthescene/ngnk-
| lsp/blob/kpath/k/lsp.k
|
| You might consider joining one of the APL forums if you
| haven't already.
| geocar wrote:
| Ok. I have some idea I think of where you are at, so I
| will give it a shot. I think this sort of thing is an
| emergent property in the design of APL applications, and
| so there's nothing to "see" in terms of an example unless
| you can see that design process.
|
| But first, "database" here is just the list of global
| variables. If that wasn't obvious, it is important.
|
| _My_ application processes weblogs, and "clicks" is the
| bit-array of which event was a click (redirect), as
| opposed to having a variable called "weblog" which
| contains a list of records each possibly having an event-
| type field.
|
| Normalizing them that acknowledges that the weblog
| (input) probably looked like the latter, but it's easier
| to do work on the former. APL makes that transformation
| very easy: Just rotate the table. In k this is flip.
| Simples.
|
| Those "domain semantics" are simply the thing I want to
| do with "clicks" which in my application comes from the
| business (users), so I want them to provide a bunch of
| rules to do that.
|
| Now with that in mind, take a look here:
|
| https://code.jsoftware.com/wiki/Vocabulary/bdot#bitwise
|
| and here:
|
| http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperS
| pec...
|
| Look _carefully_ at the tables, because they 're given in
| a slightly different way, but they are the same. And
| these are all of them, so it should be obvious at this
| point you can represent any boolean operation against any
| matrix of variables with a matrix of these numbers.
|
| For example, you might have a sql-like expression (from a
| user of your application) of x=y, and x<y and so on that
| you want to use to filter some data set.
|
| Now if you are to think about how you might do this in
| Javascript (for example; probably in scheme too) you
| would probably organise such a table as a chain of
| closures. And I think if you look at any ORM in just
| about any language you'll see this kind of pattern (maybe
| they use classes or use a tree, but these are obviously
| the same as closures), but such a tree can _only_ be
| traversed, and the closure can _only_ be called. Maybe
| you can batch or shard, but that 's it, and since I would
| bet there are a lot of dependant loads/branching in this
| tree of closures, it is slow.
|
| But if you understand that this tree is also a matrix of
| boolean operators, it is obviously parallelisable. And
| each operation is simple/cache-friendly and so therefore
| fast. This leads to your "queries" being a set of
| projected indexes or bitmaps (whichever is convenient),
| which you probably also store in global variables
| someplace (because _that_ is convenient) while you 're
| doing what you need to do (make xml, json, bar charts,
| run programs, whatever)
| geocar wrote:
| ngn's k is publicly available, around 1000 lines and readable,
| in that I can read it.
| gitonthescene wrote:
| Readable is probably in the eye of the beholder but here's a
| partially expanded version of ngn/k
| https://codeberg.org/growler/k/src/branch/expand/a.c
|
| The expansion is mechanical and thus not really at attempt at
| readability.
| dzaima wrote:
| 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
| nickzelei wrote:
| Interesting read!
|
| On a semi-related topic: I tried learning Haskell this past
| weekend out of curiosity that I last tried it some 10+ years ago
| while still in college.
|
| I found resources for it scant. Coming from more modern
| languages/tooling like Go/Rust, I also struggled quite a bit with
| installation and the build/package system.
|
| I tried the stack template generator for yesod/sqlite and after
| some 15 minutes of it installing yet another GHC version and
| building, I eventually ctrl+C'd and closed out of the window.
|
| Maybe this was a unique experience, but I'd love some guidance on
| how to be successful with Haskell. I've primarily spent most of
| my professional years building web services, so that was the
| first place I went to. However, I was taken aback by how
| seemingly awful the setup and devex was for me. I've always been
| interested in functional programming, and was looking to sink my
| teeth in to a language where there is no other option.
| itishappy wrote:
| My understanding is that Cabal has more or less supplanted
| Stack. Use GHCup to install everything, then use `cabal init`,
| `cabal run`, or `cabal repl` like you would in Go/Rust.
|
| Stack builds on top of Cabal, and used to solve a bunch of
| problems, but the reasons for it's existence are no longer
| super relevant. It still works totally fine if that's your
| thing though.
| nickzelei wrote:
| That is so interesting and is a point where GPT has failed me
| if this is true. My understanding was the stack was the
| choice due to having better ergonomics over cabal. Apparently
| that isn't true? I Found that stack init was pretty decent at
| setting up a project structure, but can't say I tried cabal
| init.
|
| I initially installed ghcup via homebrew but found that did
| not set things up correctly and had to follow the install
| from their site, which made things work more smoothly.
| shae wrote:
| The easiest and fastest way to get everything installed is
| ghcup https://www.haskell.org/ghcup/
|
| As for being successful, there are several nice books, and
| several active forums. I've gotten good answers on the Libera
| IRC network #haskell channel, and on the Haskell matrix channel
| #haskell:matrix.org
|
| If you want to get started without installing anything, there's
| the exercism track: https://exercism.org/tracks/haskell
|
| I've heard good things about Brent Yorgey's Haskell course (
| https://www.cis.upenn.edu/~cis1940/spring13/lectures.html ) but
| haven't tried it myself.
| nickzelei wrote:
| Appreciate the resources!
| cosmic_quanta wrote:
| I learned using the Haskell Programming from First Principles
| book (haskellbook.com). I don't think it goes into web
| development, but it certainly goes through the basic project
| setup.
|
| Do you think you would have benefitted from a resource like the
| Rust book? I've been toying with the idea of writing something
| similar and donating it to the Haskell Foundation
| nickzelei wrote:
| I've seen this book referenced a few times and is quite large
| from what I've seen.
|
| Not opposed to checking it out, but to your question: I
| really like the Rust book and how easy it is to find and
| read. It feels modern, up to date, and the standard for how
| to learn Rust.
| internet_points wrote:
| https://typeclasses.com/phrasebook is a good resource
| nickzelei wrote:
| This is great! I like the note at the bottom of the page that
| it is inspired by Go/Rust by example.
|
| After checking it out this is definitely on the way to what
| I"m looking for. Direct, no-nonsense examples that are easy
| to find and grok.
| WorldMaker wrote:
| I loved the book "Real World Haskell" [1] when it first came
| out in 2008. It feels like a shame it hasn't aged well and
| there hasn't been an updated edition since then. Especially
| because it was focused on things like "here's how you build
| example web services" as a good place to discuss everything
| else by having the end goal of the book's "narrative" structure
| be real world things you might build. It may still help to
| glance at a little, but things have advanced so much in the
| decade and a half since the book was written it is hard to
| recommend, but it still feels like there should be a book like
| it updated for current day to be out there to more heartily
| recommend. If there is one I don't know of it, but I haven't
| followed Haskell as much as I'd like in my professional career.
|
| [1] https://book.realworldhaskell.org/
| 0xTJ wrote:
| Seeing "all built-in functions and operators are single unicode
| symbols" stood out to me, given that APL existed well before
| Unicode did. It's not that it's wrong today, but that wasn't
| always the case. My father used APL back in high school, and that
| was before the earliest year mentioned in the "History" section
| of the Unicode Wikipedia article.
| gitonthescene wrote:
| It wasn't Unicode but it wasn't ASCII either. I think here
| unicode is probably shorthand for not ASCII.
| WorldMaker wrote:
| Unicode inherited most of APL's encoding sets from EBCDIC
| code pages. Almost no one would _choose_ to work in EBCDIC
| today, so it is practical to just say Unicode as the last
| encoding left standing (for everyone not working on legacy
| APL code on [emulated] IBM mainframe hardware).
| xelxebar wrote:
| > Array programming is similar to functional programming - the
| primary way to control execution involves composition of
| functions - but APL tends to encourage the reliance on global
| properties and sweeping operations rather than low-level
| recursion4.
|
| This AoC solution is, indeed, quite the functionista! Better yet,
| it leans heavily into point-free expressions. The style is pretty
| popular amongst APL language enthusiasts and puzzlers.
|
| That said, you actually see quite different APL styles in the
| wild:
|
| - Pointed declarative style, also a popular with functional
| programmers (e.g. anything like this[0] from the dfns workspace)
|
| - Imperative, structured programming, very common in legacy
| production systems (e.g. this[1] OpenAI API interface)
|
| - Object-oriented, also common in somewhat newer production
| environments (e.g. the HTTP interface[2])
|
| - Data-parallel style (e.g. Co-dfns[3])
|
| Heck, APL even has lexical and dynamic scope coexisting together.
| IMHO, it's truly underrated as a language innovator.
|
| [0]:https://dfns.dyalog.com/c_match.htm
|
| [1]:https://github.com/Dyalog/OpenAI/blob/main/source/OpenAI.apl.
| ..
|
| [2]:https://github.com/Dyalog/HttpCommand/blob/master/source/Htt.
| ..
|
| [3]:https://github.com/Co-dfns/Co-dfns/blob/master/cmp/PS.apl
| librasteve wrote:
| this is pretty cool
|
| i think the first raku (perl6) parser (pugs) was written in
| Haskell, certainly all the team learned Haskell before they
| started
| _glass wrote:
| Done by Audrey Tang who later on became Minister of Digital
| Affairs of Taiwan.
___________________________________________________________________
(page generated 2025-06-06 23:01 UTC)