Live data from Hacker News

APL Interpreter – An implementation of APL, written in Haskell (2024)

scharenbroch.dev

41–50 of 75 posts

Re: APL Interpreter – An implementation of APL, written in Haskell (2024)

#41
post #39

Earlier quoted context omitted.

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.

What would you consider "high-level application logic"?

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.

Re: APL Interpreter – An implementation of APL, written in Haskell (2024)

#42
post #33
post #5

[flagged]

Please don't dig up historical comments in order to diminish someone's present-day comments or work. We can't know what has happened between then and now. We detached this subthread from https://news.ycombinator.com/item?id=44196205 and marked it off topic.

Isn't referencing a source exactly the right way to go about pointing out someone is essentially lying about their background/credentials? I'm surprised people do not care about accuracy.

Re: APL Interpreter – An implementation of APL, written in Haskell (2024)

#43

Earlier quoted context omitted.

> 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?

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.

The naming conventions are nicely sadistic.

Re: APL Interpreter – An implementation of APL, written in Haskell (2024)

#44
post #29

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.

It wasn’t Unicode but it wasn’t ASCII either. I think here unicode is probably shorthand for not ASCII.

Re: APL Interpreter – An implementation of APL, written in Haskell (2024)

#45
post #9

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.

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.

Re: APL Interpreter – An implementation of APL, written in Haskell (2024)

#46

> 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.

> 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.

Re: APL Interpreter – An implementation of APL, written in Haskell (2024)

#47
post #39

Earlier quoted context omitted.

What would you consider "high-level application logic"?

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 progres…

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.

Re: APL Interpreter – An implementation of APL, written in Haskell (2024)

#48
post #39

Earlier quoted context omitted.

What would you consider "high-level application logic"?

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 progres…

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/HyperSpec...

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 xNow 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)

Re: APL Interpreter – An implementation of APL, written in Haskell (2024)

#49

> 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.

> 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…

> 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.

Re: APL Interpreter – An implementation of APL, written in Haskell (2024)

#50
post #9

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.

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

Post reply on HN