4 ms·
Looks like the site is hugged to death :-( My only experience with APL-like languages was playing with K for a few months. It's amazing, no other language can
by cousin_it 10y ago
Looks like the site is hugged to death :-(
My only experience with APL-like languages was playing with K for a few months. It's amazing, no other language can do so much in a few characters. Here's a list of hundreds of snippets: http://code.kx.com/wiki/Qidioms http://code.kx.com/wiki/Qidioms
To give a taste of K style, I'll try to explain one of those snippets here. The problem statement is to merge three arrays x, y, z under control of another array g. Don't worry, it will make sense in a moment. These are the definitions of x, y, z and g, followed by one line of code solving the problem, and the result:
x:"abcd"
y:"123456789"
z:"zz"
g:"101121211010101"
(x,y,z)[<<g]
"1a23z4z56b7c8d9"
First of all, (x,y,z) is just the concatenation of three arrays, and [] is the familiar array indexing operator. The twist is that [] can also accept an array of indices, so e.g. "ab"[0 1 1 0] returns "abba".
But the really clever bit is <<g. A single invocation of < returns the sorting permutation of an array, i.e. an array of indices x such that g[x] is sorted. After two invocations of < you get the sorting permutation of the sorting permutation. In other words, the inverse of the sorting permutation. In other words, the permutation that turns sorted g into regular g. In other words, exactly the permutation that you need to mesh x, y and z together!
By any reasonable programmer's standard, that's way too much cleverness. But if you want a lot of functionality in a few characters, that's the price to pay, and K programmers seem happy to pay it. It's also really fast, because you're combining optimized bulk operations, and dropping down to individual elements only in special cases.
- pmoriarty 10y agoWhat do you gain from using the << syntax over a verbose but reasonably clear function name like "sorted-permutation"? Clarity in function names is one of the main reasons I prefer Lisp and Scheme over languages like APL, K, and Haskell, which seem to favor the use of something like a mathematical notation, which I've always found obfuscating. This obfuscation is made worse by the aversion to comments that I've seen in some of these languages, while in Lisp and Scheme, the verbose and explicit function names are in a way self-documenting. For someone who prefers a clear and explicit programming style, the terseness of some programming languages is a real turnoff.
- RodgerTheGreat 10y agoThe function "grade up" has the symbol "<". The composition of this function with itself "<<" is not a special case- it's "grade up of grade up". Compositions of functions are first-class objects in K, so you could certainly give it a name if you like (as well as eliding some of the brackets in the above example): ordinal: <<: (x,y,z)[ordinal g] "1a23z4z56b7c8d9" (x,y,z)ordinal g "1a23z4z56b7c8d9" The idiom << is common enough, though, that K programmers learn to recognize it when they see it in code. I'd have to look up the definition of "ordinal" to be certain it did what I think, but << is totally unambiguous. Contrary to your argument, naming short idioms like ,/ << +| and so on actually makes a program less explicit.
- deleted 10y ago[deleted]
- kazinator 10y ago$ txr This is the TXR Lisp interactive listener of TXR 173. Use the :quit command or type Ctrl-D on empty line to exit. 1> (let ((l '#"abcd 123456789 zz") (i '(1 0 1 1 2 1 2 1 1 0 1 0 1 0 1))) (gun (pop [l (pop i)]))) (#\1 #\a #\2 #\3 #\z #\4 #\z #\5 #\6 #\b #\7 #\c #\8 #\d #\9) Conversion to string: 2> (let ((l '#"abcd 123456789 zz") (i '(1 0 1 1 2 1 2 1 1 0 1 0 1 0 1))) (cat-str (gun (pop [l (pop i)])))) "1a23z4z56b7c8d9" What is this gun we have armed ourselves with? It stands for "generate until nil": it generates a lazy list whose elements are formed by successively evaluating the argument expression. If the expression yields nil then the list terminates (without adding that nil as an item). The expression uses side effects. The pop macro is straight of ANSI CL. Except, in TXR Lisp, list processing stuff like `pop` works on other sequences such as character strings: we can pop the letter a out of a place which holds "abcd", leaving "bcd" in that place. This approach just "popped into my head" immediately. We also have a syntactic [...] which gives us indexing (and other things). We also have #"..." which is a "word list literal". Simply, #"foo bar baz" means ("foo" "bar" "baz"). Note there is no quote there to prevent the evaluation of this as a form; so we still have to use one. I won't bother implementing the apparent requirement that the indices be digit characters from a string; I consider it a serious blemish on the language, if it's doing it implicitly. We can map a string of ASCII digits to the corresponding values like this: 3> [mapcar chr-digit "01234"] (0 1 2 3 4) Characters are characters, and numbers are numbers. Dynamic typing: yes please; daft typing: no thanks.
- cousin_it 10y ago> I won't bother implementing the apparent requirement that the indices be digit characters from a string; I consider it a serious blemish on the language, if it's doing it implicitly. There's no such requirement, < (and by extension <<) returns the same result for 0 1 0 2, "0102" or "abac".
- kazinator 10y agoI don't mean that the program requires the input in that form, but that the problem specification (in its strict interpretation) specifies it, and I'm missing that requirement in my solution. Obviously, there is here a language-level requirement in K that 0, "0" or "a" all denote an index zero, at least in the exemplified situation. Though that may help get points on http://codegolf.stackexchange.com http://codegolf.stackexchange.com, it comes across as rather arbitrary. We could easily acheive the same thing without pushing it into the language, at the cost of making a function call, which could have a one-letter name. 12> (defun $ (x) (cond ((numberp x) x) ((chr-digit x)) ((chr-isalpha x) (- (chr-tolower x) #\a)))) 13> ($ #\b) 1 14> [mapcar $ "cdba"] (2 3 1 0) 15> [mapcar $ #(1 3 9 5)] #(1 3 9 5) 16> [mapcar $ "012a3"] (0 1 2 0 3) We basically have to operate under the assumption that writing a function is unacceptable, and I could cater to that view easily by having this function in the TXR Lisp standard library in the next release (probably not under the name $, to reserve that for users). I am rather too convinced of its lack of utility to do such a thing.