5 ms·
I doubt that K can reduce line count by a factor 1000 though. The examples in the article is mostly about shorter identifiers like "!" instead of "range" and a
by goto11 7y ago
I doubt that K can reduce line count by a factor 1000 though. The examples in the article is mostly about shorter identifiers like "!" instead of "range" and a compact notation. That is perhaps a factor 5 not a factor 1000.
The example with a for-loop for summing a range is a blatant strawman. In which modern language would that be idiomatic?
Furthermore the examples only show a particular use case: Processing lists of numbers. How does the benefits measure up for all the other stuff a million-line program does?
That said, if you really have a million-line program doing mostly numerical processing, then I'm sure it would be a massive benefit to switch to a programming language optimized for this task.
- pwdisswordfish2 7y ago> The example with a for-loop for summing a range is a blatant strawman. In which modern language would that be idiomatic? Golang? Oh, you said modern. Never mind.
- iateanapple 7y ago> That is perhaps a factor 5 not a factor 1000. I’ve personally found 20-30x compared to Java - admittedly not the most compact language.
- jmnicolas 7y agoI'd rather read 30 lines of Java (yes Java !) than try to decipher one line of K !
- tluyben2 7y agoMatter of taste; I cannot imagine having to program Java (give me Clojure/Scala any time if jvm is required) for a living anymore; deciphering a lovely 200000 class codebase where every call in every 30 lines bring you into a deep spelunking trying to figure out where/how/what and hoping it's not in some ancient undocumented .jar etc. So I have very much the opposite of what you have. Then again, I have been doing k/j/apl for a long enough time that I would not call reading it deciphering, most of the time. While for Java (& C#) it is always deciphering, even after 20+ years (which was when I became a professional Java programmer) because, unlike with k, you simply cannot know all the libraries and files or the brilliant imagination of people who like to use design patterns 'just a bit' wrong for everything.
- goto11 7y ago> the brilliant imagination of people who like to use design patterns 'just a bit' wrong for everything. I assume you are comparing this to deciphering and maintaining K-code written by developers who uses all the idioms just a bit wrong?
- tluyben2 7y agoWell that would be an interesting test; it is not that easy to do that while it is absolutely trivial (I would say run-of-the-mill) to abuse design patterns.
- geocar 7y ago> I doubt that K can reduce line count by a factor 1000 though. It adds up! Consider something like this: (defun count (list) (let ((hash (make-hash-table))) (dolist (el list) (incf (gethash (cadr el) hash 0) (car el))) (let (result) (maphash (lambda (key val) (push (list val key) result)) hash) result))) That's just #:'=:
- Veedrac 7y agoPython 3.7+: Counter(elems).values() But we can play this game both ways. What's the K for (Counter(a) & Counter(b)).most_common(3)?
- geocar 7y agoIt's a little funny comparing a language with another language+plus-its-entire-ecosystem, but k fares remarkably well I think. Counter could be #:'=: (count each group) c:#:'=: Values would just be dot. Counter[x]&Counter[y] is a bit tricky to write, because while the documentation says set intersection, what they really mean is the set intersection of the keys with the lower of the values. This is entirely clear in k; First, understand I have a common "inter" function that I use frequently (it's actually called "inter" in q): n:{x@&x in y} and from there, I can implement this weird function with this: i:{(?,/n[!x;!y])#x&y} I've never needed this particular function, but I can read out the characters: distinct raze intersection of keys-of-x and keys-of-y, taking [from] x and y. It sounds very similar to definition of the function I gave above (if you realise the relationship between "and" and "lower of the values"), and this was painless to write. most_common could be: {k!x k:y#>x} but if I'm going to want the sort (in q) I might write y#desc x which is shorter. In this I can save a character by reversing the arguments: m:{k!y k:x#>y} so our finished program (once we've defined all our "helper functions" in a module) is: m[3] i . c'(x;y) So we're looking at 13 lexemes, versus 19 - a minor victory unless you count the cost of: from collections import Counter and start counting by bytes! But there's more value here: All of these functions operate on data, so whether the data lives on the disk or not makes no difference to k. That's really powerful. In Python I need more code to get it off the disk if that's where it is. I also may have to deal with the possibility the data might "live" in another object (like numpy) so either I trust in the (in)efficiency of the numpy-to-list conversion, or I might have to do something else (in which case really understanding how Counter[a]&Counter[b] works will be important!). I might also struggle to make this work on a big data set in python, but k will do just fine even if you give it millions of values to eat. These things are valuable. Now if you're interested in playing games, let's try something hard: "j"$`:x?`f It creates (if necessary) a new enumeration in a file called "x" which persists the unique index of f, so: q)"j"$`:x?`f 0 q)"j"$`:x?`g 1 q)"j"$`:x?`h 2 q)"j"$`:x?`f 0 How would you do this in Python?