kelas@prng ~ % cd /opt/llvm-project
kelas@prng llvm-project % du -hd0
14G .
kelas@prng llvm-project % 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. 1. everything what can be a vector should be a vector.
2. we can't use underscore anyway - it is an operator. * 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. 10^@[100#0.;11*!10;1.] /just for more lulz
there's also a way to mutate it in place! 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) 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. "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.
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.