
The Q Language - callinyouin
https://code.kx.com/q/tutorials/startingq/language/
======
petermora
I worked in Pascal, C/C++, Java, Python, R, Nim, Clojure, Rust, Go, Js, and
created various projects in these languages.

However, I couldn't get used to Q. I understand that it is fast, and I also
started to like the functional programming aspect of it. But oh boy, there is
no proper error messages (no, "`type" is not helpful). The short versions of
various map and apply were handy, but there are no equivalent versions with
longer names, therefore there is no way to write a code which is readable to a
non Q-expert. The strange evaluation order made it impossible for me to read
other people's code, I often started to add parentheses and checked whether
the behavior changed. There is no debugger (I used KdbStudio). Once I used
more than 16 local variables, which gave a runtime error with some strange
unhelpful error message.

I'm not questioning its usefulness, but I think that it could be much more
developer friendly without compromising speed.

~~~
geocar
I have worked in C (twenty-five years), C++, Python, Perl (twenty years),
JavaScript, Common Lisp (for ten years), OCaml, forth, postscript, and also
q/Kdb.

I think a lot can be done to improve teaching q/Kdb.

The current “best practice” is to change _you_ until it makes sense but this
takes time- anywhere from 6 months to a couple years based on your other
experiences. And you still have to _want_ to “get it”.

I want that to be better.

However this is alien technology: the terseness is a _feature_. Limited locals
are a feature. The evaluation order is a feature. These things actually help
it go fast (as surprising as that is!)

We only just recently got “a debugger” and good error messages because of
repeated complaints and wishes for it from newbies, but there is a _reason_
experienced Kdb/q programmers never wanted it. Why doesn’t that reason prompt
those newbies to figure out why?

Yes, ideally you would learn the way and the why we do things, but there are a
number of serious hurdles to overcome: To you q/Kdb seems merely unpolished
even if maybe “fast”. Is it worth it? “Maybe”, you suggest, but then there are
crazy people like me telling you something preposterous; that q/Kdb is
actually incredibly well crafted, highly readable and an absolute pleasure to
use.

I'm also trying to say that everything is worth learning: Nim and Python and
JavaScript are all basically the same thing. You learned one of them, you
_kindof_ learned them all, so adding another one feels like these things are
easy to learn. Alien technology is alien though, _you haven 't learned any of
it_. How can we even talk to each other?

I'm hopeful: Lambda was tricky, but it snuck in to things. Can we get tables,
views, and high code density?

We need to find something better- some better way to talk about it, but the
peanut gallery is loud.

~~~
hoosieree
> Nim and Python and JavaScript are all basically the same thing. You learned
> one of them, you kindof learned them all, so adding another one feels like
> these things are easy to learn. Alien technology is alien though, you
> haven't learned any of it. How can we even talk to each other?

This is an understatement. It helps explain why a person who has never
programmed will pick up APL/J/K easier than someone who already knows Python
or C.

~~~
icen
One of the things that the GP complains about is evaluation order - in k it
follows a simple rule very consistently - programs are evaluated top to
bottom, and each expression is evaluated right to left. There are no
precedence rules. The instance that I see trip people up all the time is the
cast operator $ - people coming from other languages like C or Java expect
this to bind more tightly than other operators, but doesn't.

------
beaumayns
I mostly love K/Q, and recently rearranged my career to do more of it. There
are some things to be aware of, though:

* If your code doesn't spend most of its time in primitive verbs operating on large vectors, it's gonna be more or less as slow as any other interpreted language. Q and kdb+ can be fast and beautiful if you can arrange your problem in the right way, but it's not magic.

* The internals are locked away. If you don't like the way something fundamental works, tough. I've known some folks to go to heroic lengths with debuggers and hacked up shared objects to get Q to do what they want. You could also get Kx to add the stuff you need (they're pretty reasonable and responsive). But, you can't really take it apart and put it back together again like you can with, say, Lua, Ruby, or Python.

* Relating to the above point, one of the weaknesses of the language is that there are a lot of useful (even necessary) features packed into weird corners. There's little room for abstractions beyond the basics, so you get stuff like CSV parsing controlled by the structure of lists passed to a function called "0:". It's getting better documented lately, but it's still not pretty.

* Various annoyances (no real module system, no lexical scoping, etc...)

In many of those cases, I'm not even sure what could be done without
compromising some other aspect of the language. Most of the time (at least for
me), it's really a joy to use.

~~~
Bootvis
Curious to know what you did to rearrange your career.

------
jonathanapp
Notes from my KX/kdb experience:

1.) The in-memory DB .exe was around 500 KB. Imagine that.

2.) The Q language syntax, while consistent, is fairly arcane and throwback to
decades past.

3.) The documentation and driver support is abysmal.

4.) It's supposedly extremely fast, but I can't help but wonder if this is a
lot of successful PR and hype (like hedge fund bosses insisting on Oracle
because it's the only db that 'scales')

~~~
ktamura
I used to use KX/kdb/Q/K daily for several years. I wrote a full
implementation of reinforcement learning (15 lines), a lightweight MVC
framework (to show reports and tables in an internal webapp) and even a Q
syntax checker (abusing table as a data structure to hold parse trees). Good
or bad, for the longest time, Q was my "go-to" programming language.

Based on that experience...

1) Yes, but that's not huge by modern standard.

2) Q is a DSL version of K. As others have commented, K is a pretty clean
implementation of APL, and Q makes K more approachable.

3) I have to agree here, but Q for Mortals makes up for it.

4) It is really fast. As we all know, a vast majority of us actually don't
have terabytes and terabytes of data, especially after a reasonably cleanup /
ETL / applying common sense. I suppose it helped that I worked in finance,
which meant my desktop had 16GB of memory in 2009 and 128GB of memory on a
server shared by 4-5 traders.

Finally, Q was never intended for general-purpose computing nor a widespread
adoption. At least when I was an active user, the mailing list had the same
20-30 people asking questions and 3-4 people answering them, including
a@kx.com (= Arthur Whitney, the creator). Back then, I'd say there were at
most 2-3k active users of Q/K in the world. Now that Kx Systems is part of
First Derivative and has been working on expanding their customer base,
perhaps they have more...?

~~~
nkurz
_1) Yes, but that 's not huge by modern standard._

OP could have phrased it better, but I presume his point was that 500KB is
extremely small by modern standards. The whole executable fits comfortably in
L3, so you'll probably never have a full cache miss for instructions. On the
other hand, while it's cool that it's small, I'm not sure that binary size is
a good proxy for performance. Instruction cache misses are rarely going to be
a limiting factor.

~~~
beagle3
> Instruction cache misses are rarely going to be a limiting factor.

k's performance is a combination of a lot of small things, each one
independently doesn't seem to be that meaningful. And yet, the combination
screams.

The main interpreter core, for example, used to be <16K code and fit entirely
within the I-cache; that means bytecode dispatch was essentially never re-
fetched or re-decoded to micro instructions, and all the speculative execution
predictors have a super high hit rate.

When Python switched the interpreter loop from a switch to a threaded one, for
example, they got ~20% speedup[0]; I wouldn't be surprised if the fitting
entirely within the I-cache (which K did and Python didn't at the time) gives
another 20% speedup.

[0] [https://bugs.python.org/issue4753](https://bugs.python.org/issue4753)

~~~
nkurz
_And yet, the combination screams._

Yes, I presume it's very fast because of a number of smart design decisions. I
would guess that the relatively small on-disk size of executable is a
consequence of these decisions, rather than a cause of the high speed. And as
you point it, it's really the design of the core interpreter that matters.

 _When Python switched the interpreter loop from a switch to a threaded one,
for example, they got ~20% speedup[0]; I wouldn 't be surprised if the fitting
entirely within the I-cache (which K did and Python didn't at the time) gives
another 20% speedup._

I'm familiar with this improvement, and talk it up often. Since certain
opcodes are more likely to follow other opcodes (even if they are globally
rare) threaded dispatch can significantly reduce branch prediction errors. But
despite not having measured the number of I-cache misses on the Python
benchmarks, I'd be utterly astonished if there were enough of them to allow
for a 20% speedup. My guess would be that the potential is something around
1%, but if you can prove that it's more than 10% I'd be excited to help you
work on solving it.

~~~
beagle3
I am not involved with k, and things might have changed significantly, but
around the 2003-2005 timeframe, Arthur had very conclusive benchmarks that
showed I-cache residence makes a huge difference (IIRC I-cache was just 8KB
those days ...).

The people who surely know what difference it makes today are Nial Dalton and
Arthur Whitney.

~~~
nkurz
_around the 2003-2005 timeframe, Arthur had very conclusive benchmarks that
showed I-cache residence makes a huge difference_

That sounds quite plausible. The front-end of Intel processors (the parts that
deal with making sure there is a queue of instructions ready to execute by the
backend) has made some major advances since then. The biggest jumps were
probably Nehalem in 2007, and then Sandy Bridge in 2009.

It's not that binary size no longer matters, but you almost have to go out of
your way to make instruction cache misses be the tightest bottleneck on a hot
path. And when it would be the bottleneck, the branch predictor and prefetch
are so good that it's usually only a problem when combined with poor branch
prediction, so it really only adds to the delay rather than causing it.

------
noblethrasher
Q was the subject of an awesome presentation by Tim Thornton at YOW! Lambda
Jam 2016.

[1]
[https://www.youtube.com/watch?v=ZGIPmC6wi7E](https://www.youtube.com/watch?v=ZGIPmC6wi7E)

~~~
geocar
His description of primality testing in that video is really quite good[1]. If
it starts too slow, maybe that's a good place to start?

[1]:
[https://youtu.be/ZGIPmC6wi7E?t=9m56s](https://youtu.be/ZGIPmC6wi7E?t=9m56s)

------
dasmoth
Aside: has anyone heard any recent news about the K5/K6 rewrites of the
underlying interpreter? There was a fair amount of chatter about these a
couple of years ago, but all gone rather quiet...

(Some context:
[http://archive.vector.org.uk/art10501320](http://archive.vector.org.uk/art10501320))

~~~
RodgerTheGreat
Currently it looks like k7 is going to be an actual commercial product in the
near-ish future. Arthur is still hashing the details out, but the language
design is substantially similar to k6. If anyone ideas or strong opinions
about how to make k7 better, now would be a pretty good time to email Arthur.

For those not already in the loop with respect to k6, the reference card
([http://kparc.com/k.txt](http://kparc.com/k.txt)) provides a good overview.
Note that it is neither exhaustive nor completely representative of the
current state of the language.

------
nz
Found this illuminating interview with Arthur in the ACM queue:
[http://queue.acm.org/detail.cfm?id=1531242](http://queue.acm.org/detail.cfm?id=1531242)

------
is0tope
I have been an on and off q user for a few years. KDB+/Q is a great system,
but in my opinion it is best used for its correct purpose;and that purpose is
primarily time series and data streaming.

The columnar structure of the DB as well as its IPC layer make it very good at
creating chains of processes that can be used to stream row updates and branch
them out to different processes with different responsibilities. Likewise it's
on disk database is great for running complex (time series) queries.

This speed and terseness comes at a cost of being fairly "old school" in its
approach. It's only recently for instance the we got stack traces, and
readability is definitely not for the faint of heart though this depends on
how it is written.

In my view the biggest thing that is needed right now is better tooling and
libraries. Some attempts have been made to do this, and I am hearing that the
new initiatives by kx will be addressing this in the coming months. The lack
of standardized testing library/framework also can be problematic, as every
team that I have seen does it slightly differently, and a "best practice"
would beneficial.

------
SifJar
[https://learnxinyminutes.com/docs/kdb+/](https://learnxinyminutes.com/docs/kdb+/)

Another useful intro to the language

------
kuwze
On github kiyoto worked on this project[0] to help others understand Q code.

[0]: [https://github.com/kiyoto/ungod](https://github.com/kiyoto/ungod)

------
anonfunction
Conway's Game of Life in Q:

    
    
        life:{3=a-x*4=a:2(sum -1 0 1 rotate\:,’/)/x}

~~~
abraae
By comparison in APL:

    
    
      life←{↑1 ⍵∨.∧3 4=+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂⍵}

~~~
LfLxfxxLxfxx

      life←{≢⍸⍵}⌺3 3∊¨3+0,¨⊢
    

[https://youtu.be/3FjYly2G_QI?t=565](https://youtu.be/3FjYly2G_QI?t=565)

~~~
RodgerTheGreat
I think I've nearly convinced Arthur to include an equivalent to "stencil" in
k7. Fingers crossed!

~~~
Avshalom
K's approach of arrays of arrays would preclude an efficient 2d stencil
operation wouldn't it?

------
aamederen
As an outsider, my initial reaction is "does every new database system have to
come up with their own SQL-like language?"

~~~
beagle3
SQL's only virtue is that it is well known; It is otherwise not very good
compared to other query languages, and every SQL engine extends it somewhat
differently, extensions which you can't avoid cause the standard is too
limited. I agree most query languages would be better off as minor extensions
to SQL - but kdb+/Q is different.

Unlike SQL which pays lip service to Codd's relational model but breaks it
with things like TOP, ORDER BY, LIMIT and others, the Q language embraces the
order between tuples to great effect, making e.g. "as-of" queries which are
quite common trivial; whereas in SQL and the relational model, as-of queries
are inefficient in either execution time or storage space (usually both), and
reasonable execution speed schemas cannot, in fact, guarantee their integrity
(which is often quoted as one of the the main advantages of the relational
model).

As another example, Q implements "foreign key chasing" also called "reference
chasing", which is also implemented in the web2py DAL and surely others;
compare[0] the equivalent tpc-h query:

in q:

    
    
       select revenue avg supplier.nation=`BRAZIL by order.date.year from lineitem
        where order.customer.nation.region=`AMERICA, order.date.year in 1995 1996, part.type=`STEEL
    

in sql:

    
    
       select o_year,sum(case when nation = 'BRAZIL' then revenue else 0 end)/sum(revenue) as mkt_share
       from(select year(o_orderdate) as o_year,revenue,n2.n_name as nation
        from part,supplier,lineitem,orders,customer,nation n1,nation n2,region
        where p_partkey = l_partkey and s_suppkey = l_suppkey and l_orderkey = o_orderkey
         and o_custkey = c_custkey and c_nationkey = n1.n_nationkey
         and n1.n_regionkey = r_regionkey and r_name = 'AMERICA' and s_nationkey = n2.n_nationkey
         and o_orderdate between date('1995-01-01') and date('1996-12-31') and p_type = 'STEEL') 
        as all_nations group by o_year order by o_year;
    

[0] bottom of [http://kparc.com/d.txt](http://kparc.com/d.txt)

------
anonu
Q is great. I think wider adoption would come from two places:

1\. adding more syntactic sugar to the language to improve readability

2\. open-sourcing the thing or building an open-source compatible Q
interpreter with all the nice features of KDB (functional programming, vector-
based data structures, "scripting language within a database" approach, web
features: HTTP server and websockets, etc.. etc.. )

------
pyvpx
what makes kdb so special and why isn't there an open/libre alternative?

~~~
beagle3
But there are:

k variants:

kona (C, interpreter):
[https://github.com/kevinlawler/kona](https://github.com/kevinlawler/kona)

klong (C, interpreter): [http://t3x.org/klong/](http://t3x.org/klong/)

kuc (C++, JITted): [http://althenia.net/kuc](http://althenia.net/kuc)

oK (JS, interpreter):
[https://github.com/JohnEarnest/ok](https://github.com/JohnEarnest/ok) (see
also iKe by John Earnest)

cousins:

J (C, interpreter) [http://jsoftware.com/](http://jsoftware.com/)

A+ (C, interpreter, unmaintained):
[http://www.aplusdev.org/index.html](http://www.aplusdev.org/index.html)

Gnu APL (C, interpreter):
[https://www.gnu.org/software/apl/](https://www.gnu.org/software/apl/)

apl.js (JS, interpreter):
[https://github.com/ngn/apl](https://github.com/ngn/apl)

There's also NARS2000 and a few other APL interpreters

related:

Numpy and R provide similar functionality, albeit with more verbose (and less
fluent) composability. They are usually slower.

~~~
anonu
Nice list of alternatives. But the original question was what makes it so
special? What does it have that these open-source variants don't?

~~~
ColanR
For a certain set of applications, I believe the difference is speed. K has
been said to even outpace C, even though that's the language it's written in.
AW did an amazing job with his optimizations.

------
cousin_it
I used to play with K long ago, it was tons of fun. Sometimes I think I
should've been a quant and made crazy money :-)

------
amypinka
The next time you buy some stock, thank the Q language for making it happen.

------
fiatjaf
What is this?

~~~
amypinka
Documentation for kdb+/q. MS had a posting for their new Q# language today on
HN so that might have inspired someone to post this.

------
modeless
The KDB code is terse to an unhealthy extreme. Check this gem:

    
    
        // remove more clutter
        #define O printf
        #define R return
        #define Z static
        #define P(x,y) {if(x)R(y);}
        #define U(x) P(!(x),0)
        #define SW switch
        #define CS(n,x)	case n:x;break;
    

[https://github.com/KxSystems/kdb/blob/master/c/c/k.h#L96](https://github.com/KxSystems/kdb/blob/master/c/c/k.h#L96)

Or this wall of code:

[https://github.com/KxSystems/kdb/blob/master/c/c.cs](https://github.com/KxSystems/kdb/blob/master/c/c.cs)

~~~
kolme
Welp, you were not kidding:
[https://github.com/KxSystems/kdb/blob/master/c/c/curl.c](https://github.com/KxSystems/kdb/blob/master/c/c/curl.c)

This code is basically obfuscated by hand. Absolutely unapproachable. Only the
original author(s) can understand it.

Judging by other comments, it seems to work well. So they seem to be good
programmers producing working code. It's just not intelligible by other human
beings, which is a pretty bad thing, but not the only factor in software
quality/health.

The Vim code base is at some parts straight batshit insane, but it's one of
the most polished programs I've ever used.

All that being said, I would find infuriating to work with such code. Nope!

~~~
beagle3
It takes time getting used to, yes.

And it is not for all people.

But it's just a foreign language; You could look at Japanese text[0] and make
similar statements, and would be just as valid (or rather, invalid) as your
statement.

You expect to be able to read it because you're used to a class of languages
which are all similar enough at the surface level -- perhaps you are even
familiar with more than one fundamentally different classes, say, "lispish and
algolish" or "germanic and latin". But that doesn't make APLish or Japanese[0]
horrible.

This is just APL using C syntax.

[0] assuming, the proverbial you does not know Japanese

~~~
marshray
The difference between "#define Z static" and Japanese is that Japanese is an
effective method of communicating between 125 million people.

~~~
PaulRobinson
And k/q is an effective method of writing very fast software for domains such
as finance understood by thousands of people.

Just because you find it strange, it does not mean it's strange.

I'm sure you'd find languages in Papua New Guinea difficult at times, and
you'd argue English is "better" because more people speak it, and there is a
richer literature in it, but the ideas expressed in those languages - and how
they are expressed uniquely in those languages - are valuable to the people
who speak them.

~~~
marshray
No one here said it was strange. The original word was 'unhealthy'.

I'd be very interested to learn more about which semantics of APL-derivatives
correspond to which of the 4 or 5 distinct meanings of the keyword 'static' in
C.

------
feelin_googley
This is only software I have ever seen that actually got _smaller_ over time.

Not only that, it is the only software I have ever seen that used a GUI and
then ditched it in a subsequent version.

Few programs are so aligned with my own software sensibilities.

Only complaint is that they used to have a FreeBSD port and now only have
Linux and macOS but no BSD.

Unfortunately Linux compat in BSD is being perceived by some as a potential
security issue these days.

~~~
oskarth
> This is only software I have ever seen that actually got smaller over time.

I agree, this is admirable!

Even if it is under different names (which I think is a far better approach),
Sustrik does this too: [http://250bpm.com/blog:50](http://250bpm.com/blog:50)
He went from AMPQ (not his own creation) -> ZeroMQ -> nanomsg -> Libmill
(essentially Go in C/UNIX style)

Also, OpenBSD comes to mind (LibreSSL for example).

~~~
beagle3
Libmill/Libdill (go coroutines) are not on the
AMPQ->ZeroMQ->Crossroads->Nanomsg (socket abstraction) path ; in fact, they
have essentially nothing in common except sustrik.

~~~
oskarth
I wish you'd actually read the article before shooting your mouth off with a
Well Actually. FTA:

> Next one: nanomsg. An alternative to ZeroMQ.

In comments:

> How would you split nanomsg, then?

> [...] 2. coroutine library, e.g. libtask, libmill [...]

Not to mention that this is obvious if you understand what the core of each
thing is in terms of capabilities. If you are gonna be the "technically..."
guy, at least do it right.

It's about decomposing things, which is the essence of good design, and -
supposedly - the UNIX philosophy at its heart.

~~~
dang
Commenting like this will get you banned on HN regardless of how much you know
or how right you are. Please reread the site guidelines (linked at bottom of
every HN page) and take them to heart from now on.

------
tree_of_item
More APL threads for anyone interested:

Smaller Code, Better Code:
[https://news.ycombinator.com/item?id=13565743](https://news.ycombinator.com/item?id=13565743)

AMA: Explaining my 750 line compiler+runtime designed to GPU self-host APL:
[https://news.ycombinator.com/item?id=13797797](https://news.ycombinator.com/item?id=13797797)

------
http-teapot
Imagine being French and having to explain you code in Q.

(I am not certain if my comment follows HN's guidelines, apologies if I
offended anyone)

~~~
xamuel
The French got their revenge by giving us Coq

------
human_afterall
For a second I thought you meant Q# - got pretty excited there :)

------
johnhenry
Not directly related, but Microsoft just released a new language for
developing quantum languages, Q#, which doesn't seem to be related at all. I
hope this doesn't cause too much confusion.

------
scottyelich
... and can you use the 32bit version in commercial use? (Last I checked,
no...)

The license already changed once (for the worse, IMnsHO), so what's to say
that won't happen again. Too risky to touch.

No, can't use it (32bit version) for commercial, so this is a non-starter.
Sorry.

kOS? really?
[https://news.ycombinator.com/item?id=8475809](https://news.ycombinator.com/item?id=8475809)

~~~
beagle3
You can purchase a license if you want to be unaffected by future license
changes. It might not be the right price for you, but it is for some. They
are, in fact, courting only rich customers.

Some languages are worth learning to expand your horizons. Lisp is one of
them, even if you never use it, and the APL family (of which K/Q are members)
is another. My C code has become faster, simpler, shorter and less buggy after
I dabbled in K. YMMV, but using it in a commercial setting is not the only
reason to look at it.

> kOS? really?
> [https://news.ycombinator.com/item?id=8475809](https://news.ycombinator.com/item?id=8475809)

Really. What exactly is your "really?" question?

~~~
vram22
>My C code has become faster, simpler, shorter and less buggy after I dabbled
in K.

Interesting. Can you explain why you think that has happened?

~~~
beagle3
Several things:

1\. K (and the entire APL family) eschew many of the layers upon layers of
abstraction that modern software engineering uses, whether they are justified
or not. It turns out, that they are mostly not justified. K gently pushes you
toward thinking in a lower level of "what's really happening here?"; I'm not
sure I can give a good example here - but the world looks different after
taking the red pill. e.g., it is not uncommon in K to represent a tree as an
two arrays, one of data, and one of parent pointers. Once you shake the "but I
must abstract this!" feeling, you realize it works better.

2\. K gently encourages doing work on batches of data. That is, it is
idiomatic (and easier) to write functions that operate on arrays, and return
arrays of processed data, then writing functions that operate on one element
at a time. In turn, this means that the resulting program more often than not
works in stages where each stage processes its entire input before going to
the next stage (which uses the output from this stage as its input). In the
"old" C/C++/C#/Java/Python world, it is idiomatic to push each element through
a pipeline before going to the next one.

3\. K encourages building a set of orthogonal, non trivial operations and
combining them in various ways, rather then building layer upon layer of
abstraction. It gives an example by giving an extremely useful basis of
functions. E.g. [http://nsl.com/k/t.k](http://nsl.com/k/t.k) implements a very
fast, reasonably capable in memory database with aggregation, joins, projects
and more. It takes all of 14 lines, all quite short. While you can't implement
it in 14 lines of C, using the same principles you can probably do that in
less than a hundred. Achieve the same in idiomatic C is going to be much
harder and longer.

4\. Finally, K gently encourages solutions which work well with modern memory
and storage hierarchies. E.g., it encourages linear scan operations that touch
all elements of an array over random access ones that touch only 1/10 of the
elements. Instinct and idiom in other languages will guide you towards the
latter, but the former is often much faster.

~~~
vram22
Also, I had been looking at J (again) recently, and noticed that it has a
similar concept of composing operations as K does. I guess it is because both
are from the APL family of languages, as shown in the "Influenced" section
here:

[https://en.wikipedia.org/wiki/APL_(programming_language)](https://en.wikipedia.org/wiki/APL_\(programming_language\))

~~~
beagle3
Yes, APL is the ancestor; Arthur Whitney wrote A, a miniature APL interpreter
which inspired Roger Hui’s implementation of J (designed by Ken Iverson who
previously designed APL).

J optimized for purity, K for practicality.

I remember reading a commentary from Iverson that, despite J’s beauty and
theoretical niceness, at least two practical choices made by K turned out to
be better:

1\. Doing left-to-right scan and fold; this is inconsistent with parsing, but
turns out to be significantly more useful

2\. K’a minimalistic currying (juxtaposition) is not as nice theoretically as
J’a trains and forks, but turn out to be much more useful in practice.

However, I don’t remember where I read that and cannot find the source now.

