HNHacker News
TopNewBestAskShowJobs

kelas

53 karma · joined December 4, 2013

[ my public key: https://keybase.io/kelas; my proof: https://keybase.io/kelas/sigs/WXWZmUQknz3jMk0HH8EukP31NeZYN300HjdXKRoAvNA ]
submissionscomments
kelas··on Don't Force Your LLM to Write Terse [Q/Kdb] Code: An Information Theory Argument
oh no, not really.

this is not writing in assembly, and definitely not in bytecode.

but if you are indeed an elite intel(R) assembly coder, and old enough for eax and rax to have taken too much toll on you, or your time away from your family, and of your career as a computer programmer in general - you should probably consider a more modern, more simple and elegant isa, which is now omnipresent, royalty-free, has a huge encoding margin for custom extenstions, and spares you from the childhood trauma of 16 GPRs. it is called riscv.

k family languages isn't asm. it doesn't expect you to hardly ever need anything other than x,y,z in terms of function arguments. this is why they are so conveniently implicitly auto-declared for you in your function - just reference them, done.

it is useful, man. it works.

kelas··on Don't Force Your LLM to Write Terse [Q/Kdb] Code: An Information Theory Argument
author of the annotated version here.

> representative example

this is grossly taken out of context (which is explicitly stated at the very top of the corresponding readme, https://github.com/kparc/ksimple).

ioccc is often brought up in such HN rants, but the comparison is off mark completely. if you can't read this, you're better off writing some python or some such. this works exactly because it is not obfuscated. this code can't be more regular. tripwires (lack of malloc errno check, possible overflow of refcount) are given as exercises.

> Is there some kind of brain surgery you have to undergo when you accept the q license that damages the part of the brain that perceives beauty?

this code has absolutely zero to do with commercial system k4/kdb+, where did you get that idea? this is published under MIT license. would you like to be reminded of the terms, or fancy an explanation of what they mean? all of them implicitly state that if you're unhappy with the terms you're very welcome to walk away.

hopefully, no brain surgery required for you, god forbid. just an open mind, in methaphorical sense, healthy sense of humour and common sense that the less you type the more you think.

you are also welcome to share examples of code which tickle your sense of beauty, authored by you or someone else.

now, stand straight and defend your argument. we're all ears.

kelas··on Zoo of array languages
> If you're arguing that "Read-Eval-Print cycle" doesn't count as REPL, then it pretty strongly undercuts your argument that "dialog approach".

no, thankfully, it doesn't, and here's why. as i elucidated above, PDP-1 was indeed a revolutionary "el cheapo" computer, which DEC managed to ship over 50 units of. it gave birth to hacker culture, just because it had to be hacked with all kinds of peg legs in order to be useful. now, to the point:

1. PDP-1 is mostly remembered for Spacewar!, a groundbreaking space combat game invented by a dude who also coincidentally invented large parts of LISP while on IBM payroll.

2. APL, after its debut in 1965-1966, had its first official application to teach formal methods in systems design at NASA Goddard Center.

My point should be obvious, but just in case:

in our line of work (between sessions on Hacker News) we are sometimes faced with the concept of "production" (usually on Friday afternoons). this idea really matters. it makes all the difference between fooling around and the real deal.

therefore, as it must follow, and as i mentioned much earlier, APL was and remains the very first real REPL system, although they didn't really use that terminology. all i meant is that in 21st century people take Chrome's devconsole, ipython, node, zsh for granted. with completions, hints, all that.

(in APL'esque family, by the way, there's hardly anything to hint or auto-complete. mathematics doesn't work that way. by the way, not coincidentally, one of the most successful modern descendants of APL is called Wolfram Mathematica)

are we on the same page?

kelas··on Zoo of array languages
this is a gross undeappreciation of a truly remarkable effort by my dear friend and associate. also, at least one of the languages presented is due to him. you can call him @ktye. he's too modest.

it is not a Kunstkamera or some computer cryptozoology extravaganza. many things are shown here, from different eras, but some are not - they are evolving. and progress takes sacrifice.

cheers k.

ps. we usually spell atw as atw :) he also goes by a. don't chicken out, send him an email. he's a very friendly guy. just like me.

kelas··on Zoo of array languages
(well, at least the mf is big in japan now lol)
kelas··on Zoo of array languages
julia is cool, hands down.

only typical k binary will be less than 200kb and doesn't need stdlib. it still needs a few syscalls, but we're working on that.

and julia has this small and insignificant dependency called llvm. i bullshit you not:

  kelas@prng ~ % cd /opt/llvm-project
  kelas@prng llvm-project % du -hd0
   14G .
  kelas@prng llvm-project %
kelas··on Zoo of array languages
> Or, do you just not do that sort of stuff in these languages?

i tell you more. it is very much recommended to avoid doing this sort of stuff in all languages.

  v_sepallength: 11 14 12
  v_sepallthickness: 1.3 1.5 1.2
  mul[v_sepallength;v_sepalthickness]
no:

   /sepal:lengths and stroke widths
   spl:[l:11 14 12;w:1.3 1.5 1.2]    /this is your "struct", if you will
  
   spl.w
  1.3 1.5 1.2    /proof

   */spl
  14.3 21. 14.4  /for mul, we don't even have to bother with field names

   */spl`l`w     /but if you insist, lets make it explicit
  14.3 21. 14.4

to produce a "factory" for well-formed spl objects is a no-brainer as well.

why we don't use v_ prefix:

  1. everything what can be a vector should be a vector.
  2. we can't use underscore anyway - it is an operator.
kelas··on Zoo of array languages
exactly.

the complexity is built differently in k.

  * namespaces do exist, and are just as useful as they are in c++ and especially my beloved *sun.misc.unsafe*. i recommend.

  * instead of passing 20 arguments to a function (which is impossible - the limit is lower), we pass a dictionary if we have to. k **pretends** that everything is passed by value, but in reality it is much smarter than that.

  * notion of *scopes* is a bit of a non-sequitur here, but it is fundamentally important that there is no *lexical scoping* in k. the only two scopes which are available from the scope of a lambda are exactly *local* and *global*. and for as long as your function doesn't mess around with global scope or i/o (which is essentially the same thing), it remains pure, which is super cool. this design is not just for simplicity - it is for a good reason, and more than one.

  * the above doesn't mean that it is impossible to create a *closure* in k and pass it around as a value.

  * functions take up to three implicit arguments - named x,y and z (they can be renamed explicitly, but why not just document their semantics instead, in-situ?). all you need to do to declare xyz is reference them in the function definition. in competent k code, you'll rarely see a function with more than xyz.

 * in k community, we don't use upper case unless the apartment is on fire. god forbid.

 * shorter names and more documentation, and there will be joy.
kelas··on Zoo of array languages
> t=\:t:!x

this is of course obvious first idea, but the recipe from above is actually from the official k4 cookbook. t=t is less innocent than it seems, i'm afraid.

in k7/k9, we can:

  10^@[100#0.;11*!10;1.]    /just for more lulz
there's also a way to mutate it in place!
kelas··on Zoo of array languages
nice :) also see here:

https://news.ycombinator.com/item?id=45603661

HN is such a sweetheart. i should check in more often.

kelas··on Zoo of array languages
> That is wildly disingenuous.

assuming you're referring to numpy as to have anything to do with python spec, i totally agree with you. only it doesn't. so don't pytorch and pandas (and good so, poor python doesn't need any extra help to be completely f).

> you get an nxn identity matrix by...

no, man, that's how you get it. really advanced technique, kudos!

i get it by:

   id:{...}     /there are many ways to implement identity in k, and it's fun!
   id 3
  +1.00 +0.00 +0.00
  +0.00 +1.00 +0.00
  +0.00 +0.00 +1.00
but if you can keep a secret, more recently we've gotten so lazy and disingenuous in k land, and because we need them bloody matrices so often now, we just do it like so:

   &3
  +1.00 +1.00 +1.00
  +1.00 +1.00 +1.00
  +1.00 +1.00 +1.00

   =3
  +1.00 +0.00 +0.00
  +0.00 +1.00 +0.00
  +0.00 +0.00 +1.00
(but of course before we do that we first install python4, numpy, pytorch, pandas and polars - not because we need them, just to feel like seasoned professionals who know what they're doing)
kelas··on Zoo of array languages
ok, you have a point there. all 53 PDP-1s were "cheap" computers compared to IBM stuff (only $1M, adjusted) and used paper drum instead of punch cards. that was a nightmare to deal with, so people were buying IBM M typewriters to punch stuff in. Although Deutsch and Berkeley's LISP was in large part a copycat of IBM's LISP, people were indeed typing in LISP expressions in a REPL'ish manner. But if you ever saw a line of LISP, you can imagine what kind of "REPL" that was. "Miss one paren" comes to mind :)

APL\360 used a much more advanced selectric with a dedicated typeball, was designed for a machine of a totally different class, and could not be compared to literally kilometers of paper containing mostly mistyped parentheses. it was TRULY terse, expressive and interactive.

but yeah, PDP-1 hackers technically got there first - they had no choice :) check this out:

https://s3data.computerhistory.org/pdp-1/DEC.pdp_1.1964.1026...

6-7 Input and Output, System Operation is where the READ-EVAL-PRINT is indeed mentioned. but if you read the entire paragraph, and the next one ("if the system drops dead" lol) you'll agree that PDP-1 "REPL" was hell on earth, at the very end of the manual there are some really juicy REPL expressions :)

LISP was a torture compared to short and powerful APL notation.

less code less bug.

kelas··on Zoo of array languages
for that matter, i always wonder how people mistake python for numpy :) they have surprisingly little in common.

but enough talking about languages that suck. let's talk about python!

i'm not some braniac on a nerd patrol, i'm a simple guy and i write simple programs, so i need simple things. let's say i want an identity matrix of order x*x.

nothing simpler. i just chose one of 6 versions of python found on my system, create a venv, activate it, pip install numpy (and a terabyte of its dependencies), and that's it - i got my matrix straight away. i absolutely love it:

  np.tile(np.concatenate([[1],x*[0]]),x)[:x*x].reshape(*2*[x])
and now lets see just how obscure and unreadable exactly the same thing looks in k:

  (2#x)#1,x#0
no wonder innocent people end up with brain aneurisms and nervous breakdowns.
kelas··on Zoo of array languages
> without it being tacit, it would probably be more readable

definitely. tacit can be taken a bit too far sometimes, but when a certain discipline is observed (just like in any language, really) it is no less readable than... let me see. oh, lets take some typical pandas/polars heroics - no, those things don't give me brain aneurisms and not too shocking either. they just make wanna vomit no less than the poor people who were forced to write it and contemplate what they've done.

> tacit is "bad"

not at all. it takes one time to see how avg looks in explicit notation to understand that the idea of trains is totally justified.

> the question of how to thread data around without naming it is an interesting one to me.

good question. see above - yes indeed, things can be taken to extremes. when an apl/k program is a oneliner 80 chars long, that's just not cool. there is no reason not to break it down a bit into moving parts with names (and ample space on the right margin for annotations). in no way APL and friends are somehow exempt from commenting their code. but that's not really endemic to array languages, you'd agree.

kelas··on Zoo of array languages
> seems to disagree

no, actually i think Wikipedia got it right:

  "The 1974 Maclisp reference manual by David A. Moon attests "Read-eval-print loop" on page 89, but does not use the acronym REPL.[7]
  Since at least the 1980s, the abbreviations REP Loop and REPL are attested in the context of Scheme.[8][9]"

The first APL interpreter was implemented on System/360 in 1965. Iverson got a Turing in 1979.
kelas··on Zoo of array languages
of course it runs in a browser - pretty much everything you can build using clang will run on the web. including linux kernel and llvm itself.

to hell with peanuts: i'm pretty sure someone must even built cpython interpreter to wasm target, why not. there is no limit of what can be achieved by a group of motivated people with zero sense of direction.

k, however, makes quite a bit of sense on the web - also on your phone. and time to prompt is going to be MUCH faster than python and octave. and i mean their native builds :)

https://kparc.io/k/

backslash is reference card, cmd+[] some examples

kelas··on Zoo of array languages
> your first working program feels like a happy accident.

if you don't mind sharing: how did your own first working program felt like, and what was it written in?

by the way, did it work, or did it work correctly? it's a small but important distinction.

kelas··on Zoo of array languages
> I'd call that code obfuscation.

we call them "trains". since this one has a descriptive name, `avg a`, is not cryptic at all. just a bit fewer of absolutely meaningless parens and duplication.

but it doesn't end there:

1. imagine you wanted a moving average instead. i need to change one character in this train to get `mavg`. what would you need to do?

2. imagine you want to compute moving averages for each of 1000 arrays using both instruction-level parallelism and all available cores? while you'd be writing your unobfuscated code for that, i'd be done way before you're back from your lunch break. in two keystrokes.

once you'd be done with your solution, there would be no need to discuss productivity, or so i hope, but to discuss performance would be interesting.

kelas··on Zoo of array languages
guys,

symbolic algebra package and a computer language are not the same thing :) not even remotely.

kelas··on Zoo of array languages
i'm sure niall is missing it too :)

what does he do these days?

kelas··on Zoo of array languages
in k, we say "primitive operators are verbs", and "lambdas, functions, variables, literals are nouns".

higher-order functions (over, scan, each, etc) are called adverbs.

kelas··on Zoo of array languages
> i assume that in most array languages, you also create "words" or however you want to call functions, to reuse code.

sure, that's a very useful feature, like elsewhere.

> I wonder about a purely aesthetic issue: how does it look to interleave those symbols with user-defined words that by nature will be much, much longer, i.e. "create-log-entry" or "calculate-estimated-revenue".

strictly speaking, dashes and underscores in k can't even be a part of identifier - they are core language primitives. it is very uncommon to see java-like identifiers like CalculateEstimatedRevenue, why would you want that?

to your question:

here's a bit of an oddity: all user-defined functions and core language operators can be called using functional notation:

  v:1 2 3        / some vector
    v+v          / usual infix notation, two operands: left and right
  2 4 6
   +[v;v]        / same as infix, but called as it were a function.
   2 4 6

  add:{x+y}      / a user-defined function: a lambda with a name and two operands.
  add[v;v]
   2 4 6
but there is an important distinction between the two. you can't use your `add` function infix, you must call it as a function, and there are good reasons for that:

  2 add 2         / that's not gonna work
that said, mixing language primitives with function calls looks and reads just fine:

  +/add[v;v]
 12
hope this helps!
kelas··on Zoo of array languages
oh, gosh. sorry for your loss.

if you don't mind me asking, do you also remember the day when you wrote some non-trivial program in any language and it "worked" the first time, whatever that means (i presume "correctly")? what was the language? are you sure you've made a full recovery from that shock as well?

on a serious note, APL (and, by proxy, its descendants) invented REPL (dubbed "dialogue approach") long before the people who coined "REPL" even came to be. When that happened, C lanugage wasn't around either. Fortran was, granted, and sure enough it "worked" every time. you didn't even have to try, just punch it up on a punchcard, stick it in, wait a while. done. flawless.

on a closing note: writing correct programs takes skill and happens in iterations. the faster you can iterate, the faster you can justify your money's worth. the less you type, the more you think. less code less bug.

does that help?

kelas··on Zoo of array languages
numpy is also an array language, with a userbase that of (R+k)^10

never seems to make these lists :)

kelas··on Why LLMs Can't Write Q/Kdb+: Writing Code Right-to-Left
thanks, and you're welcome.

i hope you'll find them useful.

kelas··on Why LLMs Can't Write Q/Kdb+: Writing Code Right-to-Left
no, it wasn't your choice how you were taught to read and write something like this:

1|2*3>>4+5

in C and k, this expression should hopefully evaluate to 1, but this is just a lucky coincidence: reading and writing these two expressions are wildly different in complexity in those two languages. if you're not sure what i mean, ask your local LLM to explain why that is, but make sure you're sitting down. what you'll discover is that what you think you "simply chose to do" is not what you're actually doing.

while it is true that you can write code anyway you deem fit, i'm afraid you're a bit confused about the actual direction you're forced to think you chose to write it.

but once you're there, it suddenly gets a lot less complicated, and - miraculosly - doesn't cancel out or mess up your previous beliefs and habits.

k/q, of apl heritage, are beautiful - first and foremost because they're simple to write and simple to read.

kelas··on Why LLMs Can't Write Q/Kdb+: Writing Code Right-to-Left
(en passant, k is arguably more lispy than some lisps. for a lisp guy, the first cultural shock is usually the absence of 99% of superfluous parens)

as for LLM copilots and the quality of their lisp: why you'd expect them to excel in lisp better than they lisp in excel, pardon the pun?

kelas··on Why LLMs Can't Write Q/Kdb+: Writing Code Right-to-Left
curiously enough,

this thread made me revisit some past conversations with people like atw, nsl and aab with regard to possible ways to expose humans to the way rivers flow in k/q/apl land. the choices are limited, and decision takes some agony:

a) if you don't want your audience to close the tab right away, you'd say "a k expression is written, read and evaluated strictly right to left unless the precedence is explicitly overridden by parens, and this works better than you think, no worries, you'll come around. by the way, parens are evil, avoid them if you can".

b) if your intent is to retain a sharper crowd who went to yale or something, you'd say "a k expression is to be understood right of left", and throw them a freebie in form of a prompt for their local LLM in order to get lit. the magic sequence is just "f g h x leibniz".

for my own selfish reasons, i always chose the former, and it seems to perform better than the latter, proof:

https://github.com/kparc/ksimple

https://github.com/kparc/kcc

still, neither approach is anywhere near the chances of successfuly explaining which way to write python code to a 5yo kid, especially its precedence rules, which are much more intuitive (lol).

to explain the same thing to an LLM is not much different, really. all you need to do is to depress your 0yo kid with an obscene amount of _quality_ python code, of which there is no shortage. obviously, the more python code is fed to LLMs, the more humans will paste more LLM-generated python code, to be fed back to LLMs, ad lemniscate.

(and don't mind the future tense, we are already there)

============

so this is why LLMs can't write k/q/apl. first, they haven't seen enough of it. second, they are helpless to understand the meaning of a quote which was once chosen to helm a book known as SICP, not to mention countless human counterparts who came across it earlier, to the same effect:

"I think that it's extraordinarily important that we in computer science keep fun in computing. When it started out it was an awful lot of fun. Of course the paying customers got shafted every now and then and after a while we began to take their complaints seriously. We began to feel as if we really were responsible for the successful error-free perfect use of these machines. I don’t think we are. I think we're responsible for stretching them setting them off in new directions and keeping fun in the house. I hope the field of computer science never loses its sense of fun. Above all I hope we don’t become missionaries. Don't feel as if you're Bible salesmen. The world has too many of those already. What you know about computing other people will learn. Don’t feel as if the key to successful computing is only in your hands. What's in your hands I think and hope is intelligence: the ability to see the machine as more than when you were first led up to it that you can make it more."

― Alan J. Perlis

kelas··on Just use HTML
No, brother - a neon tube requires at least a 4kV transformer, she's not so easy going. And in 2025 there are still absolutely valid use cases for CRT oscilloscopes, lamp amplifiers, LPs and Compact Cassettes, if you're old enough to know what those things are. But arithmometers are only useful to have fun under influence, sorry. Don't be a luddite.

A modern web browser, on the other hand, is the closest the humanity ever got to building a tower of Babylon, which is very easy to see by spending a few hours exploring how the Chromium sausage is made. I'm not aware of any worse codebase out there in the wild, and it is definitely not glowing neon.

On yet another hand, there are good news - it is just a matter of time when DOM API will get properly exposed to WASM VM, and on that sunny day all script kiddies, along with nodejs kiddies, along with endless pythonista will finally and traumatically learn the difference between the definitions of "computer programmer" and "software developer".

The day will come, and computer programming will again be art and full of fun.

You always get back to the basics, they say. But the road is long and full of sticks and stones, just like a false sheperd called 1-pixel gif. That's not yet the art of programming, sorry.

And btw I fully support HN for flagging this post. The quality of writing there is as silly as it is obnoxious.

kelas··on Just use HTML
Hard to disagree on the last part, but hand-coding HTML4 for food in 2025 is not the answer. First, it will look horrible. Second, if will look even more horrible on mobiles, which are first.

Third, if you're really determined to go piedi nudi nel parco in a modern browser, why not abandon HTML4 as well, and the dreaded 1-pixel along with it?

Just escape everything altogether, and you'll be fine. Avoid HTML5, CSS, WOFF, Canvas, and all other dreadfully slow and bug-ridden APIs. You'll be fine, take my word for it. All you need, really, is unobstructed access to target GPU, which will be orders of magnitude faster than all API bs and still do more than HTML4 ever could. For one example, can you figure out how the following page manages to render an HTML page with Garamond Math on it without loading any Garamond Math to begin with and no HTML to write home about? Network tab is a good start:

https://kel.as

Buckle up and enjoy the ride.

Page 1 of 3Next →