Live data from Hacker News

Impending kOS

archive.vector.org.uk

181–190 of 242 posts

Re: Impending kOS

#181
post #105

Earlier quoted context omitted.

That was awesome, thanks for explaining that for us. It makes a lot of sense the way you explain it, and I quickly got the idea that you can make some powerful expressions this way. The smooth creation of lists is I think one of the most important language features higher level languages have over lower level languages like C. Just this thing: c::a$"\n" That's all I needed to be convinced that modern languages should…

that seems overly complicated for ruby if a is a file. c = []; a.lines{c As far as $, you may know it from Regex as the new line indicator.

a is a mapped string. You could do:

    c=[];n=0;a.lines{|x|c
but $"\n" wasn't special, and this allocates tons of memory. tinco's implementation is much closer to what k is actually doing.

Re: Impending kOS

#182
post #179

Earlier quoted context omitted.

> similar in capability to SQL but around 1000x faster If it's really similar in capabilities, why not strap an SQL parser on it and sell it? You can do it client-side to avoid wasting performance where it matters. Surely there's money to be made in the database business if you are an order of magnitude faster than everyone else -- let alone three .

You don't seem to be aware that Arthur did exactly that: http://code.kx.com/wiki/Startingkdbplus/qlanguage http://www.kx.com/q/d/kdb+.htm http://www.kx.com/q/d/kdb+1.htm It's a commercial product and I understand kx does pretty well.

I was not. Thank you. What is the source of the performance figures?

Re: Impending kOS

#183
post #126
post #37

Earlier quoted context omitted.

If someone produces smaller and faster code than me, then I should want to learn from it. I wonder why other people have the exact opposite reaction. Why do you think that is?

I do enjoy learning about such things, but, for most of the work I do, performance is nowhere near at the top of the list of things I care about. Also in the past I've been burned by code that's small/fast but is otherwise utterly unmaintainable. I'm not saying that's the case here, but... past experience, and all that tends to color perceptions. I think with a language like k or q, which appears to be purpose-built…

One benefit to a short program is that there's not much code to rewrite if you can't read something.

This doesn't happen very often, but I find the thought comforting.

Re: Impending kOS

#184

Earlier quoted context omitted.

Oh goodness... don't do scan like that. Way easier (and more efficient) to use a generator: def scan(f, iterator, initial=0): yield initial yield from scan(f, iterator, f(initial, next(iterator))) Even with python2, you could make a non-recursive version that'd be still shorter than your scan and faster. Alternatively, you could pair a coroutine with that reduce function.... But always be suspect of your code if you…

First, it is not equivalent - next() cannot apply to range() output, for example - you will need to do some iter() games and watch out for iteration order side effects if your values are iterators vs. lists. Second, it is ~10% faster, but that speed difference disappears completely if you eliminate the namespace lookup (that is, add e.g. "o = r.append" before the loop, and call o() instead of r.append() inside the lo…

> First, it is not equivalent - next() cannot apply to range() output, for example - you will need to do some iter() games and watch out for iteration order side effects if your values are iterators vs. lists.

It uses generator/iteration semantics instead of list semantics. If you wrap the whole thing with a decorator like function that does:

    def scan_wrapper(f, x0, x):
        return list(scan(f, iter(x), x0)
You get the exact same semantics. For most cases (including the one you cited), the alternate semantics are actually better, more flexible, and avoid requiring a list to be built in the first place.

No problem with iteration order side effects either unless your f() somehow invalidates your iterable... and you still have some potential exposure there in your original implementation.

> Second, it is ~10% faster... > It potentially uses less memory...

Yeah, I think you are understating it to say the least. Not only are you using less memory, but you are saving having to rejuggle/resize the list all the time.

> (unless Python 3 gained TCO when I wasn't looking. Did it?)

I guess in a way it sort of did for the case of yield from: 'The iterator is run to exhaustion, during which time it yields and receives values directly to or from the caller of the generator containing the yield from expression (the "delegating generator").'

So, even without full on TCO (which is still possible... I'm not sure if they did it with yield from), you at least have direct pass through from the generator to the caller. Because of iterator semantics, that should mean that each of the generators gets created on an as needed basis and the previous generator should get destroyed right thereafter. It is possible though that it isn't quite doing it right, in which case I'll concede that I'm still allocating an N deep generator stack, but that is still likely to be more memory efficient because it isn't having to reallocate/resize/copy increasingly larger lists throughout the execution.

> recursive solutions without TCO are rarely good enough to replace iteration.

As I mentioned, you can do the recursive solution as well, and it has the advantage of working with old Python. Still simpler and still far more efficient (here it is with extra wrapping to keep the semantics the same):

    def scan(f, x0, x):
        def scan_helper():
            yield x0
            for x1 in x:
                x0 = f(x0, x)
                yield x0
        return list(scan_helper())
> It is mostly space-efficient in general.

You say that like when doing statistical analysis space-efficiency isn't a concern...

> I think it is more idiomatic, though - and also Python2 compatible - to just replace references to 'r' with yield in my code, than using the recursive definition you gave above - which is more idiomatic in functional languages, but less in Python (and harder to debug in any language than the iterative version)

I was actually mostly getting at using yield instead of list append. I was just trying to express it as tersely as possible, which unsurprisingly became Python 3 and a functional style mechanism.

While I agree that often there is a struggle to understand functional programming, I think in this case it is very idiomatic Python (particularly since they defined "yield from" specifically for cases like this), and the code is very simple, readable, and easier to verify for correctness.

Re: Impending kOS

#185
Does a good formal introduction exist for K, or Q, or APL, or J, or any other languages in this family? Something with, you know, a syntax definition at least, and any kind of formal definition of the semantics.

The closest I could find is this [1] but "The model is expressed in SHARP APL", so from the start, it's circular.

[1] http://www.jsoftware.com/papers/APLSyntaxSemantics.htm

Re: Impending kOS

#186
post #34

> kOS is coming. Nothing will be the same afterwards. There seems to be this strange idea going around that if we just get the right tool, everything else is going to change forever. I see this a lot with people trying to create IDEs that let non-programmers create programs without really knowing how to code. But the thing is, most people just don't have anything worth coding. The problem isn't that the tools don't e…

If I am from another planet, and say I don't know why programs are so big and slow and buggy, and the most complicated program you see I've produced is a glorified calculator, it's too easy to be patronising and say well, that's because you haven't done anything complicated . However if I then show you a programming language, a database engine (similar in capability to SQL but around 1000x faster), a graphical deskto…

Having studied the History of Mathematics, I think that the same discussion/argument must have occurred in Italy when transitioning from Roman to Arabic numerals.

Would you rather do:

IXDCCCLVI * VIIDCCCXLIX

or

9856 * 7849 ?

Re: Impending kOS

#187
post #87

Earlier quoted context omitted.

I'll give this a shot. I'll try to explain what's in my mind as I read it as well. First, get out the reference manual: http://kparc.com/k.txt and we'll do the first couple lines. The sequence that goes f x applies x to f. this f is unary. The sequence that goes x f y applies x and y to f. this f is binary (and just labelled verb). Some things (adverbs) go f a x and apply f in some special way to x. Last hint: You re…

Wow, that was fascinating. K looks utterly mind-expanding, thanks for breaking this down. You obviously have some experience working with K, and it sounds like at least Javascript, too? K is so foreign I expect it has a lot of interesting thoughts locked up in there that maybe don't get the attention they deserve. Would you say there are any "killer features" of the language / environment that you miss when working w…

And now with less snark :).

K/Q/kdb+ deploys a single executable and some additional k code (Q is written in k) in with no changes.

Re: Impending kOS

#188

Earlier quoted context omitted.

First, it is not equivalent - next() cannot apply to range() output, for example - you will need to do some iter() games and watch out for iteration order side effects if your values are iterators vs. lists. Second, it is ~10% faster, but that speed difference disappears completely if you eliminate the namespace lookup (that is, add e.g. "o = r.append" before the loop, and call o() instead of r.append() inside the lo…

> First, it is not equivalent - next() cannot apply to range() output, for example - you will need to do some iter() games and watch out for iteration order side effects if your values are iterators vs. lists. It uses generator/iteration semantics instead of list semantics. If you wrap the whole thing with a decorator like function that does: def scan_wrapper(f, x0, x): return list(scan(f, iter(x), x0) You get the ex…

> Second, it is ~10% faster... > It potentially uses less memory...

> Yeah, I think you are understating it to say the least.

I actually measured it. It was 10% faster with a call to 'r.append', and within 0.1% with the append lookup hoisted out of the loop, on 1000 external iterations over 50,000 list items, minimum of 3, inconsistent which version was faster. my scanned function was def f(x,y): return max(0,x+y)

> You get the exact same semantics. For most cases (including the one you cited), the alternate semantics are actually better, more flexible, and avoid requiring a list to be built in the first place.

range() on Python3 is not a list, and the original works on it and yet you needed scan_wrapper(). I didn't try to fix it - I just tried to use your version and stumbled on the differences.

> but that is still likely to be more memory efficient because it isn't having to reallocate/resize/copy increasingly larger lists throughout the execution.

Instead you allocate a generator state each time. Surprisingly, it doesn't make a difference in practice (I've measured) - the python lists grow exponentially, so we have e.g. 20 allocations+copies instead of 1,000,000 generator state allocations. I would have expected the list to be faster - but there's no measurable difference.

> As I mentioned, you can do the recursive solution as well, and it has the advantage of working with old Python. Still simpler and still far more efficient (here it is with extra wrapping to keep the semantics the same):

Recursive takes about 10 times more memory. Seriously - no TCO means call stacks are not free. Instead of one object which I stored, you store about 10 in each call frame!

But yes, your latest version is the idiomatic preferred version style, IMO: it's also the most efficient. (And unlike the earlier python3 functional, it doesn't need a helper to fix the INPUT)

> You say that like when doing statistical analysis space-efficiency isn't a concern...

Of course it's a concern. I'm not saying it is not useful, I'm saying it is overrated, especially when compared to recursive solutions, which -- in python -- cost about 10 times more in stack space then you save in list space.

> I was just trying to express it as tersely as possible, which unsurprisingly became Python 3 and a functional style mechanism.

... and taking much more memory in the process, though believing that you are using less. Not blaming you - python overlooks these things. One of K's nice features is that the costs are mostly evident on a cursory look.

> I think in this case it is very idiomatic Python (particularly since they defined "yield from" specifically for cases like this), and the code is very simple, readable, and easier to verify for correctness.

The recursive functional version is speedwise comparable, and spacewise much less efficient than my (admittedly, stupid) version. It is easier to prove formally, but harder to debug with a debugger because of the generator stack (which is a call stack, even though it does not exhaust the C call stack like regular calls do).

Can we agree that your latest scan(), if we dropped the two lines that have "scan_helper" in them, is the most efficient, most idiomatic, most (py2 and py3) compatible and clearest?

Re: Impending kOS

#189
post #81

Earlier quoted context omitted.

So would k be even faster if it were compiled to machine code rather than being interpreted? Would that involve an unacceptable speed versus space trade-off? Or am I missing some crucial reason why k code has to be interpreted?

According to wikipedia's uncited 'performance characteristics' section of their page on K (programming language): > The small size of the interpreter and compact syntax of the language makes it possible for K applications to fit entirely within the level 1 cache of the processor. Sounds like the overhead's acceptable? . Edit: the following page (2002) says > Even though K is an interpreted language, the source code i…

Thanks for the link to kuro5hin btw - it's a nice intro to k but also I've not been on k5 for years, I had no idea it was still going :)
Post reply on HN